Files
2015-01-06 17:37:39 +01:00

155 lines
4.9 KiB
C++

#include "MemoryMgr.h"
#include "Malloc.h"
#include "../Logger.h"
// TODO: Use memoryNotificationCallback to notify the CLR when memory is low
SHMemoryManager::SHMemoryManager(HostContext* context) {
m_cRef = 0;
memoryNotificationCallback = NULL;
hostContext = context;
}
SHMemoryManager::~SHMemoryManager() {
if (memoryNotificationCallback)
memoryNotificationCallback->Release();
}
// IUnknown functions
STDMETHODIMP_(DWORD) SHMemoryManager::AddRef() {
return InterlockedIncrement(&m_cRef);
}
STDMETHODIMP_(DWORD) SHMemoryManager::Release() {
ULONG cRef = InterlockedDecrement(&m_cRef);
if (cRef == 0) {
delete this;
}
return cRef;
}
STDMETHODIMP SHMemoryManager::QueryInterface(const IID &riid, void **ppvObject) {
if (riid == IID_IUnknown || riid == IID_IHostMemoryManager) {
*ppvObject = this;
AddRef();
return S_OK;
}
*ppvObject = NULL;
return E_NOINTERFACE;
}
// IHostMemoryManager functions
STDMETHODIMP SHMemoryManager::CreateMalloc(DWORD dwMallocType, IHostMalloc **ppMalloc) {
*ppMalloc = new SHMalloc(dwMallocType, hostContext);
if (*ppMalloc == NULL) {
return E_OUTOFMEMORY;
}
return S_OK;
}
STDMETHODIMP SHMemoryManager::VirtualAlloc(void *pAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect, EMemoryCriticalLevel eCriticalLevel, void **ppMem) {
DWORD dwThreadId = GetCurrentThreadId();
Logger::Info("VirtualAlloc: %d bytes, critical level %d", dwSize, eCriticalLevel);
bool belowMemoryLimit = hostContext->OnMemoryAcquiring(dwThreadId, dwSize);
*ppMem = NULL;
if (eCriticalLevel > eTaskCritical || belowMemoryLimit) {
*ppMem = ::VirtualAlloc(pAddress, dwSize, flAllocationType, flProtect);
if (*ppMem == NULL) {
DWORD errorCode = GetLastError();
Logger::Error("VirtualAlloc error: %d", errorCode);
return HRESULT_FROM_WIN32(errorCode);
}
else {
hostContext->OnMemoryAcquire(dwThreadId, dwSize, *ppMem);
return S_OK;
}
}
else {
Logger::Error("Above memory limits, and critical level is too low. Returning E_OUTOFMEMORY");
return E_OUTOFMEMORY;
}
}
STDMETHODIMP SHMemoryManager::VirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType) {
Logger::Info("VirtualFree: %d bytes", dwSize);
if (::VirtualFree(lpAddress, dwSize, dwFreeType)) {
hostContext->OnMemoryRelease(lpAddress);
return S_OK;
}
else {
DWORD errorCode = GetLastError();
Logger::Error("VirtualFree error: %d", errorCode);
return HRESULT_FROM_WIN32(errorCode);
}
}
STDMETHODIMP SHMemoryManager::VirtualQuery(void *lpAddress, void *lpBuffer, SIZE_T dwLength, SIZE_T *pResult) {
Logger::Info("VirtualQuery: at address 0x%x", lpAddress);
*pResult = ::VirtualQuery(lpAddress, (PMEMORY_BASIC_INFORMATION) lpBuffer, dwLength);
if (*pResult == NULL) {
DWORD errorCode = GetLastError();
Logger::Error("VirtualQuery error: %d", errorCode);
return HRESULT_FROM_WIN32(errorCode);
}
return S_OK;
}
STDMETHODIMP SHMemoryManager::VirtualProtect(void *lpAddress, SIZE_T dwSize, DWORD flNewProtect, DWORD *pflOldProtect) {
Logger::Info("VirtualProtect: at address 0x%x", lpAddress);
if (::VirtualProtect(lpAddress, dwSize, flNewProtect, pflOldProtect))
return S_OK;
else {
DWORD errorCode = GetLastError();
Logger::Error("VirtualQuery error: %d", errorCode);
return HRESULT_FROM_WIN32(errorCode);
}
}
STDMETHODIMP SHMemoryManager::GetMemoryLoad(DWORD *pMemoryLoad, SIZE_T *pAvailableBytes) {
Logger::Info("In GetGetMemoryLoad");
MEMORYSTATUS memoryStatus;
GlobalMemoryStatus(&memoryStatus);
*pMemoryLoad = memoryStatus.dwMemoryLoad;
*pAvailableBytes = memoryStatus.dwAvailVirtual; // TODO: restrict to "available physical?"
return S_OK;
}
STDMETHODIMP SHMemoryManager::RegisterMemoryNotificationCallback(ICLRMemoryNotificationCallback *pCallback) {
this->memoryNotificationCallback = pCallback;
return S_OK;
}
// These are just reporting functions: the CLR still does file mapping by itself, but it is kind enough to inform
// us of where and how much
STDMETHODIMP SHMemoryManager::NeedsVirtualAddressSpace(LPVOID startAddress, SIZE_T size) {
// MapViewOfFile failed, and the CLR asks us if we can do something...
Logger::Info("In NeedsVirtualAddressSpace (MapViewOfFile failed) at %x for %d bytes", startAddress, size);
// I don't think so
return S_FALSE;
}
STDMETHODIMP SHMemoryManager::AcquiredVirtualAddressSpace(LPVOID startAddress, SIZE_T size) {
Logger::Info("In AcquiredVirtualAddressSpace (MapViewOfFile called) at %x for %d bytes", startAddress, size);
hostContext->OnMemoryAcquire(GetCurrentThreadId(), size, startAddress);
return S_OK;
}
STDMETHODIMP SHMemoryManager::ReleasedVirtualAddressSpace(LPVOID startAddress) {
Logger::Info("In ReleasedVirtualAddressSpace (UnmapViewOfFile called) at %x", startAddress);
hostContext->OnMemoryRelease(startAddress);
return S_OK;
}