📄 gmmf.cpp
字号:
// @doc
//
// @module Gmmf.cpp - Global Memory Mapped File Object |
//
// The CGmmf class contains member functions that allow the
// caller to allocate global memory and automatically handle
// expanding and re-mapping the memory.
//
// Maintenance:
//
// Version Date Who What
// ------- ----------- ------ -------------------------------------
// 7.0 07/27/96 msb Created
//
#include <stdio.h>
#include <windows.h>
#include <ItkDef.h>
#include <DrvRegistry.h>
#include <LogEvent.h>
#include <DrvSystem.h>
#include <ItkErr.h>
#include "gmmf.h"
static SYSTEM_INFO Gsinf;
//
// @mfunc <c CGmmf> constructor for this class. This
// constuctor will create a memory mapped file and
// place it in the address space of the process. It
// will check the registry for run-time parameters,
// kick-off a thread responsible for freeing
// memory when it expands and create an initial global
// memory area.
//
// @parm const TCHAR * | pszApp | Name of the application using this object
//
// @parm const TCHAR * | pszKey | Registry key where parameters are stored
//
// @parm const TCHAR * | pszName | Name of memory area to be created
//
// @devnote Until someone attempts to add a block, the memory and file
// sizes will be 0. The first attempt to access the memory will
// trigger an expansion to the needed size.
//
CGmmf::CGmmf(IN const TCHAR *pszApp, IN const TCHAR *pszKey,
IN const TCHAR *pszName)
{
TCHAR szTemp[MAX_PATH],
szMemoryFile[MAX_PATH];
DWORD dwStatus,
dwSize = MAX_PATH;
//
// Set the sizes to some defaults, in case the registry
// does not contain these keys
//
m_dwFileSizeMax = FILESIZEMAX;
m_dwFileGrowInc = FILEGROWINC;
m_dwOverrunBuf = OVERRUNBUF;
m_bItsMe = FALSE;
//
// Check the registry
//
CRegistry pRegistry;
pRegistry.OpenKey(pszKey);
pRegistry.ReadValue("MaxSize", &m_dwFileSizeMax);
pRegistry.ReadValue("GrowIncrement", &m_dwFileGrowInc);
pRegistry.ReadValue("OverrunBuffer", &m_dwOverrunBuf);
dwStatus = pRegistry.ReadValue("BasePath",
(TCHAR *)&m_szBasePath,
(DWORD *)&dwSize);
if (ERROR_SUCCESS == dwStatus)
{
strcpy(szMemoryFile, m_szBasePath);
strcat(szMemoryFile, pszName);
}
else
{
m_szBasePath[0] = '\0';
strcpy(szMemoryFile, pszName);
}
pRegistry.CloseKey();
//
// If a name for the memory is specified, copy it in
//
if (NULL != pszName)
{
m_szRegionName = _strdup(pszName);
}
else
{
m_szRegionName = NULL;
}
m_hFileMap = 0;
m_pbFile = 0;
m_bShutdown = FALSE;
//
// Open the event log for this driver
//
sprintf(szTemp, "%s", pszApp);
m_pLog = new CLogEvent(szTemp);
//
// Initialize the Win32 security attributes structures
//
INIT_SECURITY_ALL(m_SecAttr, m_SecDesc);
//
// Create a static MMF that we don't have to worry about
// resizing ...
//
if (MapControlBlock(pszName))
{
//
// Start a thread to wait for remap events
//
if (StartRemapThread(pszName))
{
if (*pszName != '\0')
{
m_hFile = CreateFile(szMemoryFile,
GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE,
&m_SecAttr,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_HIDDEN,
NULL);
//
// If there is an error creating the disk file, log it
//
if (m_hFile == INVALID_HANDLE_VALUE)
{
LogError(GetLastError(), MEM_CREATE_FILE, pszName);
m_hFile = 0;
return;
}
}
else
{
m_hFile = HFILE_PAGEFILE;
}
//kyu001204 - initialize to 1: RoundUp(0,value) returns 0.
m_dwFileSizeNow = 1;
m_hFileMapRes = 0;
//
// Bump the number of instances of this object
//
InterlockedIncrement((LPLONG)&m_pCtlBlock->dwTotalInstances);
//
// Go build it
//
Create();
}
}
}
//
//
// @mfunc <c ~CGmmf> destructor for this class. This
// destructor closes memory and releases all
// the Win32 resources allocated.
//
CGmmf::~CGmmf()
{
Close(m_dwFileSizeNow);
}
//
//
// @mfunc <c Create> General routine to create the initial memory.
// This function will roundup the maximum file size
// as well as the growth increment based on the
// systems allocation granularity. This function is only
// called from the constructor.
//
// @rvalue None |
//
void CGmmf::Create(void)
{
DWORD dwMaxRgnSize;
if (Gsinf.dwAllocationGranularity == 0)
{
GetSystemInfo(&Gsinf);
}
m_dwFileSizeMax = RoundUp(m_dwFileSizeMax, Gsinf.dwAllocationGranularity);
m_dwFileGrowInc = RoundUp(m_dwFileGrowInc, Gsinf.dwAllocationGranularity);
// Reserve an address space region that is big enough to hold
// the GMMF assuming that it grew to its maximum size and the
// overrun buffer area.
dwMaxRgnSize = m_dwFileSizeMax + m_dwOverrunBuf;
// Windows NT guarantess allocation granularity so we don't
// have to force it.
m_pbFile = (PBYTE)ResAddrSpace(NULL, dwMaxRgnSize);
// Adjust the GMMF region so that it contains a MMF backed by the disk
// file's storage and a reserved region (up to the maximum size of the
// GMMF specified) immediately following the MMF.
Adjust(m_dwFileSizeNow);
}
//
//
// @mfunc <c ~ExcFilter> Stuctured Exception Handler for the Gmmf object.
// If the calling routine contains a try-except
// block specifying this routine, it will be called
// when an exception occurs. We then determine if its
// an exception we want to deal with. If it is
// determined to be attempt to expand the memory of
// this object, we call Adjust to re-size the global
// memory mapped file.
//
// @parm PEXCEPTION_POINTERS | pExpception | pointer to an exception record
//
// @rvalue EXCEPTION_CONTINUE_EXCEPTION | If successful
// @rvalue EXCEPTION_CONTINUE_SEARCH | If this is not an exception we want to deal with
// @rvalue EXCEPTION_NONCONTINUABLE | If attempting to write past the maximum allowed size
//
long CGmmf::ExcFilter(IN PEXCEPTION_POINTERS pException)
{
DWORD lDisposition = EXCEPTION_CONTINUE_SEARCH;
PEXCEPTION_RECORD pExceptionRecord = pException->ExceptionRecord;
PBYTE pbAccAddr;
//
// If its not a access violation, we don't want it
//
if (pExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
{
return(lDisposition);
}
//
// Get the address of the attempted memory access
//
pbAccAddr = (PBYTE)pExceptionRecord->ExceptionInformation[1];
//
// Check to see if we are writing into the overrun area
//
if (InRange(m_pbFile + m_dwFileSizeMax, pbAccAddr,
m_pbFile + m_dwFileSizeMax + m_dwOverrunBuf - 1))
{
RaiseException(EXCEPTION_GMMF_WRITEPAST,
EXCEPTION_NONCONTINUABLE,
0,
NULL);
}
//
// Check to see if its outside our area of interest
//
if (!InRange(m_pbFile, pbAccAddr, m_pbFile + m_dwFileSizeMax - 1))
{
return(lDisposition);
}
//
// Check to see if someone else expanded the area beyond
// what we know about
//
DWORD dwNewSize;
if (m_pCtlBlock->dwMaxSize > (DWORD)((pbAccAddr-m_pbFile+1)))
{
dwNewSize = m_pCtlBlock->dwMaxSize;
}
else
{
dwNewSize = m_pCtlBlock->dwMaxSize = (pbAccAddr-m_pbFile+1);
}
Adjust(dwNewSize);
return(EXCEPTION_CONTINUE_EXECUTION);
}
// Closes a GMMF and truncates the file to the specified size.
//
// @mfunc <c Close> Called from the destructor to cleanup all the
// Win32 resources allocated and truncate the file
// to the specified size.
//
// @parm IN DWORD | dwDiskFile | Size to truncate the file to
//
// @rvalue None |
//
void CGmmf::Close(IN DWORD dwDiskFile)
{
DWORD dwReturn;
//
// Notify the remap thread that we're shutting down
// We set the event to free it from its wait.
//
m_bItsMe = TRUE;
m_bShutdown = TRUE;
SetEvent(m_hShutdownEvent);
//
// Wait for the thread to exit. If it times out, kill it
//
dwReturn = WaitForSingleObject(m_hRemapThread,3000);
if (WAIT_TIMEOUT == dwReturn)
{
TerminateThread(m_hRemapThread,0);
}
//
// Shrink the file to its required size
//
if (m_hFile != HFILE_PAGEFILE)
{
SetFilePointer(m_hFile, dwDiskFile, NULL, FILE_BEGIN);
SetEndOfFile(m_hFile);
FlushFileBuffers(m_hFile);
CloseHandle(m_hFile);
}
//
// Unmap the view of the file, close the file-mapping object
// and free the reserved address space region
//
Clear();
m_dwFileSizeNow = 0;
m_dwFileSizeMax = 0;
m_dwFileGrowInc = 0;
m_dwOverrunBuf = 0;
m_hFileMap = 0;
m_pbFile = 0;
m_hFileMapRes = 0;
//
// Decrement the total number of object instantiations
//
InterlockedDecrement((LPLONG)&m_pCtlBlock->dwTotalInstances);
if (0 == m_pCtlBlock->dwTotalInstances)
{
TCHAR szTemp[MAX_PATH];
if ('\0' != m_szBasePath[0])
{
strcpy(szTemp, m_szBasePath);
strcat(szTemp, m_szRegionName);
}
else
{
strcpy(szTemp, m_szRegionName);
}
if (!DeleteFile(szTemp))
{
LogError(GetLastError(), MEM_DELETE_FILE, szTemp);
}
m_pCtlBlock->dwElements = 0;
m_pCtlBlock->dwMaxSize = 0;
}
//
// Since this area was malloc'ed by the _strdup
// function, we will free it here
//
if (m_szRegionName != NULL)
{
free(m_szRegionName);
m_szRegionName = NULL;
}
//
// Cleanup the "Control Block"
//
UnmapViewOfFile(m_pCtlBlock); // Unmap the virtual memory
CloseHandle(m_hCBlock); // Close the File Map Object
CloseHandle(m_hRemapThread); // Close the thread handle
CloseHandle(m_hRemapEvent); // Close the event
CloseHandle(m_hShutdownEvent); // "" " "
//
// Free our event log object
//
delete m_pLog;
}
//
// @mfunc <c Clear> This function clears the memory mapped file and
// any reserved space following it. If a memory mapped
// file actually exists and we close the handle, we
// decrement a counter of how many instances are
// currently mapped to it.
//
// @rvalue TRUE | If we were actually mapped to a memory mapped file
// @rvalue FALSE | If we had not mapped, but only reserved memory
//
BOOL CGmmf::Clear()
{
MEMORY_BASIC_INFORMATION mbi;
//
// Get the state of memory at the base of the GMMF region.
//
VirtualQuery(m_pbFile, &mbi, sizeof(mbi));
//
// Enhance our chances of running the upcoming code without
// interruption
//
Sleep(0);
if (mbi.State == MEM_RESERVE)
{
UnmapViewOfFile(mbi.AllocationBase);
CloseHandle(m_hFileMapRes);
}
else
{
UnmapViewOfFile(m_pbFile);
if (mbi.RegionSize < m_dwFileSizeMax + m_dwOverrunBuf)
{
UnmapViewOfFile((PBYTE)mbi.AllocationBase + mbi.RegionSize);
CloseHandle(m_hFileMapRes);
}
}
if (m_hFileMap != NULL)
{
CloseHandle(m_hFileMap);
m_hFileMap = NULL;
InterlockedDecrement((LPLONG)&m_pCtlBlock->dwCurrentlyMapped);
return(TRUE);
}
return(FALSE);
}
//
// @mfunc <c Construct> Allocates the memory mapped file and any
// reserved space following it.
//
// @parm IN DWORD | dwDiskFileNow | New size for the memory
//
// @rvalue None |
//
void CGmmf::Construct(IN DWORD dwDiskFileNow)
{
DWORD dwDiskFileNew = RoundUp(dwDiskFileNow, m_dwFileGrowInc),
dwStatus = ERROR_SUCCESS;
PBYTE pbTemp;
if (dwDiskFileNew > 0)
{
//
// Grow the MMF by creating a new file-mapping object.
//
m_hFileMap = CreateFileMapping(m_hFile,
&m_SecAttr,
PAGE_READWRITE,
0,
dwDiskFileNew,
m_szRegionName);
if (m_hFileMap == NULL)
{
LogError(GetLastError(), MEM_CREATE_MMF, m_szRegionName);
//
// File-mapping could not be created, the disk is
// probably full.
//
RaiseException(EXCEPTION_GMMF_DISKFULL,
EXCEPTION_NONCONTINUABLE,
0,
NULL);
}
//
// Map the new MMF at the same location as
// the previously mapped view.
//
//kyu001204 - map the size of dwDiskFileNew only:
pbTemp = (PBYTE)MapViewOfFileEx(m_hFileMap,
FILE_MAP_ALL_ACCESS,
0,
0,
dwDiskFileNew,
m_pbFile);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -