#ifndef SDI2_PAGER_PAGEFREELIST_H
#define SDI2_PAGER_PAGEFREELIST_H
#include <assert.h>
#include "SlabAllocator.h"
struct PageFreeEntry
{
struct PageFreeEntry *prev, *next;
L4_Fpage_t page;
};
class PageFreeList
{
private:
typedef SlabAllocator<PageFreeEntry> slaballoc_t;
slaballoc_t::Pool* slaballoc;
struct PageFreeEntry *head;
public:
explicit inline PageFreeList(slaballoc_t::Pool *usedallocator = NULL)
: slaballoc(usedallocator), head(NULL)
{
}
inline void setSlabAllocator(slaballoc_t::Pool &sa)
{
slaballoc = &sa;
}
inline void test() const
{
if (!head) return;
class PageFreeEntry* iter = head;
assert(iter->prev == iter);
while(iter->next != iter)
{
assert(iter->next->prev == iter);
assert(L4_Address(iter->page) <= L4_Address(iter->next->page));
iter = iter->next;
}
}
inline const struct PageFreeEntry* begin() const
{ return head; }
inline bool insert(L4_Fpage_t p)
{
test();
PageFreeEntry *newnode = slaballoc->allocate();
if (!newnode) {
assert(0);
return false;
}
newnode->page = p;
if (!head)
{
newnode->next = newnode;
newnode->prev = newnode;
head = newnode;
}
else
{
PageFreeEntry *iter = head;
L4_Word_t findaddr = L4_Address(p);
while(findaddr >= L4_Address(iter->page))
{
if (iter->next == iter)
{
iter->next = newnode;
newnode->next = newnode;
newnode->prev = iter;
test();
return true;
}
iter = iter->next;
}
if (iter->prev == iter)
{
assert(head == iter);
newnode->prev = newnode;
newnode->next = iter;
iter->prev = newnode;
head = newnode;
}
else
{
iter->prev->next = newnode;
newnode->next = iter;
newnode->prev = iter->prev;
iter->prev = newnode;
}
}
test();
return true;
}
inline bool insertNear(L4_Fpage_t p, struct PageFreeEntry *iter)
{
PageFreeEntry *newnode = slaballoc->allocate();
if (!newnode) {
assert(0);
return false;
}
newnode->page = p;
if (!iter)
{
head = newnode;
newnode->next = newnode;
newnode->prev = newnode;
}
else if (iter->next == iter && L4_Address(iter->page) <= L4_Address(p))
{
assert(L4_Address(p) >= L4_Address(iter->page));
iter->next = newnode;
newnode->next = newnode;
newnode->prev = iter;
}
else if (iter->prev == iter)
{
assert(L4_Address(p) <= L4_Address(iter->page));
assert(head == iter);
newnode->prev = newnode;
newnode->next = iter;
iter->prev = newnode;
head = newnode;
}
else
{
assert(L4_Address(p) < L4_Address(iter->page));
assert(L4_Address(p) >= L4_Address(iter->prev->page));
iter->prev->next = newnode;
newnode->next = iter;
newnode->prev = iter->prev;
iter->prev = newnode;
}
test();
return true;
}
inline void remove(struct PageFreeEntry *e)
{
if (e->prev == e)
{
assert(head == e);
if (e->next == head) {
head = NULL;
}
else {
head = e->next;
head->prev = head;
}
}
else if (e->next == e)
{
e->prev->next = e->prev;
}
else
{
e->prev->next = e->next;
e->next->prev = e->prev;
}
slaballoc->freeobj(e);
}
inline struct PageFreeEntry *findNearest(L4_Fpage_t p)
{
if (!head) return NULL;
PageFreeEntry *iter = head;
L4_Word_t findaddr = L4_Address(p);
while(findaddr >= L4_Address(iter->page))
{
if (iter->next == iter)
return iter;
iter = iter->next;
}
return iter;
}
inline L4_Fpage_t getFirstPage()
{
if (!head) return L4_Nilpage;
PageFreeEntry *use = head;
if (head->next == head) {
head = NULL;
}
else {
head->next->prev = head->next;
head = head->next;
}
L4_Fpage_t p = use->page;
slaballoc->freeobj(use);
return p;
}
inline void dump() const
{
if (!head) {
printf("PageFreeList is empty\n");
return;
}
PageFreeEntry *iter = head;
while(1)
{
printf("pfl: addr 0x%08x size %d\n",
static_cast<unsigned int>(L4_Address(iter->page)),
static_cast<unsigned int>(L4_Size(iter->page)));
if (iter->next == iter) break;
iter = iter->next;
}
}
};
#endif