sourcemod/knight/shared/KePageAllocator.cpp

149 lines
2.7 KiB
C++
Raw Normal View History

#include "KePageAllocator.h"
using namespace Knight;
struct PageInfo
{
PageInfo *next;
void *base;
};
class Knight::KePageAllocator
{
public:
size_t page_size;
size_t page_granularity;
PageInfo *free_pages;
PageInfo *page_blocks;
};
static void *ke_LumpPageAlloc(KePageAllocator *alloc)
{
void *base;
char *page;
PageInfo *lump;
size_t pagesInBlock;
#if defined KE_PLATFORM_WINDOWS
base = VirtualAlloc(
NULL,
alloc->page_granularity,
MEM_COMMIT|MEM_RESERVE,
PAGE_READWRITE);
#elif defined KE_PLATFORM_POSIX
base = valloc(alloc->page_granularity);
#else
#error "Unsupported platform"
#endif
if (base == NULL)
{
return NULL;
}
lump = new PageInfo;
lump->base = base;
lump->next = alloc->page_blocks;
alloc->page_blocks = lump->next;
page = (char *)base + alloc->page_size;
pagesInBlock = alloc->page_granularity / alloc->page_size;
for (size_t i = 1; i < pagesInBlock; i++)
{
lump = new PageInfo;
lump->base = page;
lump->next = alloc->free_pages;
alloc->free_pages = lump;
page += alloc->page_size;
}
return base;
}
KePageAllocator *Knight::KE_CreatePageAllocator()
{
KePageAllocator *alloc;
alloc = new KePageAllocator;
#if defined KE_PLATFORM_WINDOWS
SYSTEM_INFO info;
GetSystemInfo(&info);
alloc->page_size = info.dwPageSize;
alloc->page_granularity = info.dwAllocationGranularity;
#elif defined KE_PLATFORM_POSIX
alloc->page_size = sysconf(_SC_PAGESIZE);
alloc->page_granularity = alloc->page_size * 16;
#else
#error "Unsupported platform"
#endif
alloc->free_pages = NULL;
alloc->page_blocks = NULL;
return alloc;
}
void Knight::KE_DestroyPageAllocator(KePageAllocator *alloc)
{
PageInfo *info, *next;
info = alloc->page_blocks;
while (info != NULL)
{
next = info->next;
#if defined KE_PLATFORM_WINDOWS
VirtualFree(info->base, 0, MEM_RELEASE);
#elif defined KE_PLATFORM_WINDOWS
free(info->base);
#else
#error "Unsupported platform"
#endif
delete info;
next = info;
}
info = alloc->free_pages;
while (info != NULL)
{
next = info->next;
delete info;
info = next;
}
}
void *Knight::KE_PageAlloc(KePageAllocator *alloc)
{
if (alloc->free_pages != NULL)
{
void *base;
PageInfo *info;
info = alloc->free_pages;
alloc->free_pages = info->next;
base = info->base;
delete info;
return base;
}
return ke_LumpPageAlloc(alloc);
}
void Knight::KE_PageFree(KePageAllocator *alloc, void *page)
{
PageInfo *info;
info = new PageInfo;
info->base = page;
info->next = alloc->free_pages;
alloc->free_pages = info->next;
}
size_t Knight::KE_PageSize(KePageAllocator *alloc)
{
return alloc->page_size;
}