cacheapis.cpp
来自「WinCE5.0部分核心源码」· C++ 代码 · 共 348 行
CPP
348 行
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// This source code is licensed under Microsoft Shared Source License
// Version 1.0 for Windows CE.
// For a copy of the license visit http://go.microsoft.com/fwlink/?LinkId=3223.
//
#include "cache.h"
CCache** g_cacheTable = NULL;
HANDLE g_hResizingEvent;
CRITICAL_SECTION g_csAddRemove;
DWORD g_dwTotalEntries = DEFAULT_NUM_TABLE_ENTRIES;
DWORD g_dwCurEntries = 0;
#ifdef DEBUG
DBGPARAM dpCurSettings = {
TEXT("DiskCache"),
{
TEXT("Init"),
TEXT("APIs"),
TEXT("Error"),
TEXT("Disk I/O"),
TEXT(""),
TEXT(""),
TEXT(""),
TEXT(""),
TEXT(""),
TEXT(""),
TEXT(""),
TEXT(""),
TEXT(""),
TEXT(""),
TEXT(""),
TEXT("")
},
ZONEMASK_DEFAULT
};
#endif
CCache* GetCache (DWORD dwCacheId)
{
WaitForSingleObject (g_hResizingEvent, INFINITE);
if (dwCacheId >= g_dwTotalEntries || !g_cacheTable[dwCacheId]) {
DEBUGMSG(ZONE_ERROR, (TEXT("GetCache: Invalid Cache ID: %d.\n"), dwCacheId));
return NULL;
}
return g_cacheTable[dwCacheId];
}
/* CreateCache
*
* Creates a new cache.
*
* ENTRY
* hDsk - An FSDMGR disk handle.
* dwStart - Starting disk block to cache
* dwEnd - Ending disk block to cache
* dwCacheSize - Size of the cache, in blocks
* dwBlockSize - Size of each block, in bytes. This must be equal to the sector size.
* dwPriority - The priority (256) for the lazy-writer thread in a write-back
* cache. Not used for write-through cache
* dwCreateFlags - Can be one or more of the following:
* CACHE_FLAG_WARM - Preload the cache on init.
* CACHE_FLAG_WRITEBACK - Allow for write-back cache.
*
* EXIT
* Cache ID that can be used on subsequent cache operations. INVALID_CACHE_ID on error.
*/
DWORD CreateCache( HDSK hDsk, DWORD dwStart, DWORD dwEnd, DWORD dwCacheSize, DWORD dwBlockSize, DWORD dwCreateFlags)
{
DWORD dwCacheId;
BOOL fError = TRUE;
DWORD dwMappingSize;
EnterCriticalSection (&g_csAddRemove);
if (!g_cacheTable) {
g_cacheTable = (CCache**)LocalAlloc (LMEM_ZEROINIT, g_dwTotalEntries * sizeof(CCache*));
if (!g_cacheTable)
goto error;
}
// If we have filled the table, double its size
if (g_dwCurEntries == g_dwTotalEntries) {
ResetEvent (g_hResizingEvent);
CCache** newTable = (CCache**)LocalReAlloc (g_cacheTable, 2 * g_dwTotalEntries * sizeof(CCache*), LMEM_ZEROINIT | LMEM_MOVEABLE);
if (!newTable) {
DEBUGMSG(ZONE_ERROR, (TEXT("CreateCache: Could not create any more caches. Table full. \n")));
SetEvent (g_hResizingEvent);
goto error;
}
g_cacheTable = newTable;
g_dwTotalEntries *= 2;
SetEvent (g_hResizingEvent);
}
// Make sure block size is a power of 2 and less than the buffer size
if ((dwBlockSize & (dwBlockSize - 1)) || (dwBlockSize > BUFFER_SIZE)){
DEBUGMSG(ZONE_ERROR, (TEXT("CreateCache: Invalid block size (%d)\n"), dwBlockSize));
goto error;
}
// The size of the cache should not be greater than the number of sectors it
// maps to on disk
dwMappingSize = dwEnd - dwStart + 1;
if (dwMappingSize < dwCacheSize) {
dwCacheSize = dwMappingSize;
}
// Find the first empty cache entry
for (dwCacheId = 0; dwCacheId < g_dwTotalEntries; dwCacheId++) {
if (!g_cacheTable[dwCacheId]) {
g_cacheTable[dwCacheId] = new CCache (hDsk, dwStart, dwEnd, dwCacheSize, dwBlockSize, dwCreateFlags);
break;
}
}
// Should never hit this, otherwise there is an inconsistency.
ASSERT (dwCacheId < g_dwTotalEntries);
// We allow a cache size of 0, meaning we always read/write directly to disk. Create buffers only if
// cache size is non-zero.
if (dwCacheSize) {
CCache* pCache = g_cacheTable[dwCacheId];
// Create cache buffer pool and lookup table
if (pCache && !pCache->InitCache()) {
delete pCache;
g_cacheTable[dwCacheId] = NULL;
goto error;
}
}
g_dwCurEntries++;
fError = FALSE;
error:
LeaveCriticalSection (&g_csAddRemove);
return fError ? INVALID_CACHE_ID : dwCacheId;
}
/* DeleteCache
*
* Deletes a cache. This will free all memory allocated.
*
* ENTRY
* dwCacheId - The cache ID returned by CreateCache
*
* EXIT
* ERROR_SUCCESS on success. ERROR_INVALID_PARAMETER on an invalid cache ID.
*/
DWORD DeleteCache( DWORD dwCacheId)
{
CCache* pCache = GetCache(dwCacheId);
if (!pCache)
return ERROR_INVALID_PARAMETER;
pCache->FlushCache (NULL, 0);
EnterCriticalSection (&g_csAddRemove);
delete g_cacheTable[dwCacheId];
g_cacheTable[dwCacheId] = 0;
g_dwCurEntries--;
LeaveCriticalSection (&g_csAddRemove);
return ERROR_SUCCESS;
}
/* ResizesCache
*
* Resizes a cache. The cache can either be reduced or expanded in size. If the request is to expand
* the cache, and there is not enough memory, the cache remains its original size and is not modified.
* The cache will be first flushed before resizing, and all cached entries will be lost.
*
* ENTRY
* dwCacheId - The cache ID returned by CreateCache
* dwSize - The new number of blocks of the cache.
* dwResizeFlags - Can be one or more of the following:
* CACHE_FLAG_WARM - Preload the cache on init.
*
* EXIT
* Returns ERROR_SUCCESS on success or appropriate error code on failure.
*/
DWORD ResizeCache( DWORD dwCacheId, DWORD dwSize, DWORD dwResizeFlags)
{
DEBUGMSG(ZONE_APIS, (TEXT("ResizeCache: Resizing Cache %d.\n"), dwCacheId));
CCache* pCache = GetCache(dwCacheId);
if (!pCache)
return ERROR_INVALID_PARAMETER;
return pCache->ResizeCache(dwResizeFlags, dwSize);
}
/* CachedRead
*
* If desired block is cached, then it copies data from the cache into the caller's buffer.
* Otherwise, it reads the data from disk and copies it into the caller's buffer as well
* as the cache.
*
* ENTRY
* dwCacheId - The cache ID returned by CreateCache
* dwBlockNum - Starting block to read from
* dwNumBlocks - Number of blocks to read
* pBuffer - Pointer to buffer to read data into
* dwReadFlags - Not currently used.
*
* EXIT
* Returns ERROR_SUCCESS on success or appropriate error code on failure.
*/
DWORD CachedRead(DWORD dwCacheId, DWORD dwBlockNum, DWORD dwNumBlocks, PVOID pBuffer, DWORD dwReadFlags)
{
CCache* pCache = GetCache(dwCacheId);
if (!pCache)
return ERROR_INVALID_PARAMETER;
return pCache->ReadCache (dwReadFlags, dwBlockNum, dwNumBlocks, pBuffer);
}
/* CachedWrite
*
* In the case of write-through, it writes the data both to the disk and the cache.
* In the case of write-back, it writes the data to the cache only and allows the
* lazy-writer to eventually commit the data to the disk. If the cache location
* that the data is to be written to overwrites a dirty block that is different from
* the block to be written, then that dirty block is committed to disk.
*
* ENTRY
* dwCacheId - Cache ID to read.
* dwBlockNum - Starting block number to read from
* dwNumBlocks - Number of sectors to read
* pBuffer - Buffer to read contents into
* dwWriteFlags - Can be a combination of the flags below.
* CACHE_FORCE_WRITETHROUGH - Only applies for a write-back cache.
* This will force the written blocks to be committed to disk.
*
*
* EXIT
* Returns ERROR_SUCCESS on success or appropriate error code on failure.
*/
DWORD CachedWrite(DWORD dwCacheId, DWORD dwBlockNum, DWORD dwNumBlocks, PVOID pBuffer, DWORD dwWriteFlags)
{
CCache* pCache = GetCache(dwCacheId);
if (!pCache)
return ERROR_INVALID_PARAMETER;
return pCache->WriteCache (dwWriteFlags, dwBlockNum, dwNumBlocks, pBuffer);
}
/* FlushCache
*
* Commits any dirty blocks in the cache to disk. Only needed for write-back cache.
*
* ENTRY
* dwCacheId - The cache ID returned by CreateCache
* dwFlushFlags - Not currently used.
*
* EXIT
* Returns ERROR_SUCCESS on success or appropriate error code on failure.
*/
DWORD FlushCache(DWORD dwCacheId, PSECTOR_LIST_ENTRY pSectorList, DWORD dwNumEntries, DWORD dwFlushFlags)
{
DEBUGMSG(ZONE_APIS, (TEXT("FlushCache: Flushing Cache %d.\n"), dwCacheId));
CCache* pCache = GetCache(dwCacheId);
if (!pCache)
return ERROR_INVALID_PARAMETER;
return pCache->FlushCache (pSectorList, dwNumEntries);
}
DWORD SyncCache(DWORD dwCacheId, PSECTOR_LIST_ENTRY pSectorList, DWORD dwNumEntries, DWORD dwSyncFlags)
{
return ERROR_SUCCESS;
}
DWORD InvalidateCache(DWORD dwCacheId, PSECTOR_LIST_ENTRY pSectorList, DWORD dwNumEntries, DWORD dwFlags)
{
DEBUGMSG(ZONE_APIS, (TEXT("InvalidateCache: Cache %d.\n"), dwCacheId));
CCache* pCache = GetCache(dwCacheId);
if (!pCache)
return ERROR_INVALID_PARAMETER;
return pCache->InvalidateCache(pSectorList, dwNumEntries, dwFlags);
}
/* CacheIoControl
*
* Used to extend the Cache APIs by allowing user defined cache IOCTLs.
* Any unhandled IOCTLs are passed down to the block driver.
*
* ENTRY
* dwCacheId - The cache ID returned by CreateCache
* Rest - Standard DeviceIoControl parameters
*
* EXIT
* Returns TRUE on success. FALSE on failure.
*/
BOOL CacheIoControl(DWORD dwCacheId, DWORD dwIoControlCode, LPVOID lpInBuf, DWORD nInBufSize, LPVOID lpOutBuf, DWORD nOutBufSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped)
{
CCache* pCache = GetCache(dwCacheId);
if (!pCache)
return ERROR_INVALID_PARAMETER;
return pCache->CacheIoControl(dwIoControlCode, lpInBuf, nInBufSize, lpOutBuf, nOutBufSize, lpBytesReturned, lpOverlapped);
}
BOOL WINAPI DllMain(HANDLE hInstance, DWORD dwReason, LPVOID lpReserved)
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls( (HMODULE)hInstance);
DEBUGREGISTER((HINSTANCE)hInstance);
InitializeCriticalSection (&g_csAddRemove);
g_hResizingEvent = CreateEvent (NULL, TRUE, TRUE, NULL);
break;
case DLL_PROCESS_DETACH:
DeleteCriticalSection (&g_csAddRemove);
CloseHandle (g_hResizingEvent);
LocalFree (g_cacheTable);
break;
}
return TRUE;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?