mirror of
https://github.com/ldematte/HostedPumpkin
synced 2026-06-08 15:25:15 +00:00
155 lines
4.9 KiB
C++
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;
|
|
}
|