20#include "pedigree/kernel/LockGuard.h"
21#include "pedigree/kernel/Log.h"
22#include "pedigree/kernel/processor/PhysicalMemoryManager.h"
23#include "pedigree/kernel/processor/Processor.h"
24#include "pedigree/kernel/processor/VirtualAddressSpace.h"
25#include "pedigree/kernel/utilities/MemoryPool.h"
26#include "pedigree/kernel/utilities/assert.h"
27#include "pedigree/kernel/utilities/utility.h"
29static void map(uintptr_t location) {
32 void* page =
page_align(
reinterpret_cast<void*
>(location));
39static bool unmap(uintptr_t location) {
42 void* page =
page_align(
reinterpret_cast<void*
>(location));
46 physical_uintptr_t phys = 0;
56MemoryPoolPressureHandler::MemoryPoolPressureHandler(
MemoryPool* pool) : m_Pool(pool) {}
58MemoryPoolPressureHandler::~MemoryPoolPressureHandler() {}
61 return "MemoryPool: freeing unused pages";
65 return m_Pool->
trim();
68MemoryPool::MemoryPool()
78 m_Pool(
"memory-pool"),
79 m_bInitialised(false),
81 m_ActiveOperations(0),
83 m_PressureHandler(this) {
86MemoryPool::MemoryPool(
const char* poolName)
97 m_bInitialised(false),
99 m_ActiveOperations(0),
101 m_PressureHandler(this) {
104MemoryPool::~MemoryPool() {
120 if (wasInitialised) {
125MemoryPool::ActiveOperation::ActiveOperation(
MemoryPool& pool)
126 : m_TerminationDeferral(), m_Pool(pool.beginOperation() ? &pool : nullptr) {}
128MemoryPool::ActiveOperation::~ActiveOperation() {
130 m_Pool->endOperation();
134bool MemoryPool::beginOperation() {
146void MemoryPool::endOperation() {
154 m_DrainCondition.
signal();
170 if (!poolSize || !bufferSize)
173 const size_t maxSize = ~static_cast<size_t>(0);
175 if (poolSize > (maxSize / pageSize))
177 const size_t poolBytes = poolSize * pageSize;
180 if ((bufferSize & (bufferSize - 1))) {
182 while (powerOf2 < bufferSize) {
183 if (powerOf2 > (maxSize >> 1))
187 bufferSize = powerOf2;
190 if (bufferSize > poolBytes)
195 NOTICE(
"MemoryPool: allocating memory pool '" <<
m_Pool.
name() <<
"', " <<
Dec
196 << (poolBytes / 1024) <<
Hex <<
"K. Buffer size is "
208 MemoryPressureManager::instance().
registerHandler(MemoryPressureManager::HighestPriority,
228 uintptr_t result = 0;
244 ConditionVariable::Error error = ConditionVariable::NoError;
245 if (!m_Condition.
wait(m_Lock, error)) {
268 assert(offset < poolSize);
270 result = poolBase + offset;
279 map(result + offset);
284 map(result + offset);
305 assert(buffer >= poolBase);
306 size_t offset = buffer - poolBase;
307 assert(offset < poolSize);
354 for (
size_t n = 0; n < nBuffers; ++n) {
358 if (unmap(page + off))
367 for (
size_t n = 0, m = 0; n < nBuffers; n += N, ++m) {
372 for (
size_t y = 1; y < N; ++y) {
394#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
395void MemoryPool::acquireHostedOperationLock() {
399void MemoryPool::releaseHostedOperationLock() {
403void MemoryPool::acquireHostedMappingLock() {
407void MemoryPool::releaseHostedMappingLock() {
411size_t MemoryPool::getHostedActiveOperationCount() {
void waitForCompletion(Mutex &mutex)
MUST_USE_RESULT bool wait(Mutex &mutex, Time::Timestamp &timeout, Error &error, WaitQueue::StackDiscardCleanup onStackDiscard=nullptr, void *stackDiscardContext=nullptr)
static bool mutexAcquired(Error error)
bool test(size_t n) const
virtual const char * getMemoryPressureDescription()
void free(uintptr_t buffer)
Frees an allocated buffer, allowing it to be used elsewhere.
size_t m_BufferSize
Size of each buffer in this pool.
bool m_bInitialised
Has this instance been initialised yet?
ExtensibleBitmap m_AllocBitmap
Allocation bitmap.
size_t m_ActiveOperations
Operations which entered before destruction began.
bool m_bClosing
Destruction has begun; no new operations may enter.
size_t m_BufferCount
Number of buffers we have available.
bool trim()
Trims the pool, freeing pages that are not otherwise in use.
MemoryRegion m_Pool
MemoryRegion describing the actual pool of memory.
MemoryPoolPressureHandler m_PressureHandler
Memory pressure handler for this pool.
uintptr_t allocateDoer(bool canBlock)
Allocation doer.
bool initialise(size_t poolSize, size_t bufferSize=1024)
void registerHandler(size_t prio, MemoryPressureHandler *pHandler)
void removeHandler(MemoryPressureHandler *pHandler)
const char * name() const
void * virtualAddress() const
virtual physical_uintptr_t allocatePage(size_t pageConstraints=0)=0
static PhysicalMemoryManager & instance()
static constexpr size_t getPageSize() PURE
static const size_t virtualOnly
virtual void freePage(physical_uintptr_t page)=0
virtual bool allocateRegion(MemoryRegion &Region, size_t cPages, size_t pageConstraints, size_t Flags, physical_uintptr_t start=-1)=0
bool tryAcquire(size_t n=1)
bool acquire(size_t n=1, size_t timeoutSecs=0, size_t timeoutUsecs=0)
virtual bool map(physical_uintptr_t physicalAddress, void *virtualAddress, size_t flags)=0
virtual bool isMapped(void *virtualAddress)=0
static const size_t KernelMode
virtual bool getMapping(void *virtualAddress, physical_uintptr_t &physicalAddress, size_t &flags)=0
static const size_t Write
static EXPORTED_PUBLIC VirtualAddressSpace & getKernelAddressSpace()
virtual void unmap(void *virtualAddress)=0
EXPORTED_PUBLIC void * page_align(void *p) PURE