Convert page_block to use kutil::linked_list
- Created a new linked_list-based slab allocator - Simplified memory bootstrap code by using the slab allocator and linked_lists
This commit is contained in:
@@ -48,6 +48,9 @@ public:
|
||||
/// \returns The prev node in the list
|
||||
inline const node_type * prev() const { return m_prev; }
|
||||
|
||||
private:
|
||||
friend class linked_list<T>;
|
||||
|
||||
/// Insert an item after this one in the list.
|
||||
/// \arg item The item to insert
|
||||
void insert_after(node_type *item)
|
||||
@@ -76,9 +79,6 @@ public:
|
||||
m_next = m_prev = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class linked_list<T>;
|
||||
|
||||
node_type *m_next;
|
||||
node_type *m_prev;
|
||||
};
|
||||
@@ -93,8 +93,8 @@ public:
|
||||
|
||||
list_iterator(item_type *item) : m_item(item) {}
|
||||
|
||||
inline T & operator*() { return *m_item; }
|
||||
inline const T & operator*() const { return *m_item; }
|
||||
inline item_type * operator*() { return m_item; }
|
||||
inline const item_type * operator*() const { return m_item; }
|
||||
inline list_iterator & operator++() { m_item = m_item ? m_item->next() : nullptr; return *this; }
|
||||
inline list_iterator operator++(int) { return list_iterator<T>(m_item ? m_item->next() : nullptr); }
|
||||
inline bool operator!=(const list_iterator<T> &other) { return m_item != other.m_item; }
|
||||
@@ -118,9 +118,21 @@ public:
|
||||
m_tail(nullptr)
|
||||
{}
|
||||
|
||||
/// Move constructor. Takes ownership of list elements.
|
||||
linked_list(linked_list<T> &&other) :
|
||||
m_head(other.m_head),
|
||||
m_tail(other.m_tail)
|
||||
{
|
||||
other.m_head = other.m_tail = nullptr;
|
||||
}
|
||||
|
||||
/// Check if the list is empty.
|
||||
/// \returns true if the list is empty
|
||||
bool empty() const { return m_head == nullptr; }
|
||||
|
||||
/// Count the items in the list.
|
||||
/// \returns The number of entries in the list.
|
||||
size_t length()
|
||||
size_t length() const
|
||||
{
|
||||
size_t len = 0;
|
||||
for (item_type *cur = m_head; cur; cur = cur->m_next) ++len;
|
||||
@@ -213,6 +225,66 @@ public:
|
||||
list.m_head = list.m_tail = nullptr;
|
||||
}
|
||||
|
||||
/// Append the contents of another list to the end of this list. The other
|
||||
/// list is emptied, and this list takes ownership of its items.
|
||||
/// \arg list The other list.
|
||||
void append(linked_list<T> &&list)
|
||||
{
|
||||
if (!list.m_head) return;
|
||||
|
||||
if (!m_tail) {
|
||||
m_head = list.m_head;
|
||||
m_tail = list.m_tail;
|
||||
} else {
|
||||
m_tail->m_next = list.m_head;
|
||||
m_tail = list.m_tail;
|
||||
}
|
||||
|
||||
list.m_head = list.m_tail = nullptr;
|
||||
}
|
||||
|
||||
/// Remove an item from the list.
|
||||
/// \arg item The item to remove
|
||||
void remove(item_type *item)
|
||||
{
|
||||
if (!item) return;
|
||||
if (item == m_head)
|
||||
m_head = item->m_next;
|
||||
if (item == m_tail)
|
||||
m_tail = item->m_prev;
|
||||
item->remove();
|
||||
}
|
||||
|
||||
/// Inserts an item into the list before another given item.
|
||||
/// \arg existing The existing item to insert before
|
||||
/// \arg item The new item to insert
|
||||
void insert_before(item_type *existing, item_type *item)
|
||||
{
|
||||
if (!item) return;
|
||||
|
||||
if (!existing)
|
||||
push_back(item);
|
||||
else if (existing == m_head)
|
||||
push_front(item);
|
||||
else
|
||||
existing->insert_before(item);
|
||||
}
|
||||
|
||||
/// Inserts an item into the list after another given item.
|
||||
/// \arg existing The existing item to insert after
|
||||
/// \arg item The new item to insert
|
||||
void insert_after(item_type *existing, item_type *item)
|
||||
{
|
||||
if (!item) return;
|
||||
|
||||
if (!existing)
|
||||
push_front(item);
|
||||
else if (existing == m_tail)
|
||||
push_back(item);
|
||||
else
|
||||
existing->insert_after(item);
|
||||
}
|
||||
|
||||
/// Insert an item into the list in a sorted position. Depends on T
|
||||
/// having a method `int compare(const T *other)`.
|
||||
/// \arg item The item to insert
|
||||
@@ -224,12 +296,7 @@ public:
|
||||
while (cur && item->compare(cur) > 0)
|
||||
cur = cur->m_next;
|
||||
|
||||
if (!cur)
|
||||
push_back(item);
|
||||
else if (cur == m_head)
|
||||
push_front(item);
|
||||
else
|
||||
cur->insert_before(item);
|
||||
insert_before(cur, item);
|
||||
}
|
||||
|
||||
/// Range-based for iterator generator.
|
||||
|
||||
60
src/libraries/kutil/slab_allocator.h
Normal file
60
src/libraries/kutil/slab_allocator.h
Normal file
@@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
/// \file slab_allocator.h
|
||||
/// A slab allocator and related definitions
|
||||
#include "kutil/linked_list.h"
|
||||
#include "kutil/memory.h"
|
||||
|
||||
namespace kutil {
|
||||
|
||||
|
||||
/// A slab allocator for small structures kept in a linked list
|
||||
template <typename T, typename Alloc = void * (*)(size_t)>
|
||||
class slab_allocator :
|
||||
public linked_list<T>
|
||||
{
|
||||
public:
|
||||
using item_type = list_node<T>;
|
||||
|
||||
/// Default constructor.
|
||||
/// \arg chunk_size The size of chunk to allocate, in bytes. 0 means default.
|
||||
/// \arg alloc The allocator to use to allocate chunks. Defaults to malloc().
|
||||
slab_allocator(size_t chunk_size = 0, Alloc alloc = malloc) :
|
||||
m_chunk_size(chunk_size),
|
||||
m_alloc(alloc)
|
||||
{
|
||||
}
|
||||
|
||||
/// Get an item from the cache. May allocate a new chunk if the cache is empty.
|
||||
/// \returns An allocated element
|
||||
inline item_type * pop()
|
||||
{
|
||||
if (this->empty()) allocate();
|
||||
item_type *item = this->pop_front();
|
||||
kutil::memset(item, 0, sizeof(item_type));
|
||||
return item;
|
||||
}
|
||||
|
||||
/// Return an item to the cache.
|
||||
/// \arg item A previously allocated element
|
||||
inline void push(item_type *item)
|
||||
{
|
||||
this->push_front(item);
|
||||
}
|
||||
|
||||
void allocate()
|
||||
{
|
||||
size_t size = m_chunk_size ? m_chunk_size : 10 * sizeof(item_type);
|
||||
void *memory = m_alloc(size);
|
||||
size_t count = size / sizeof(item_type);
|
||||
|
||||
item_type *items = reinterpret_cast<item_type *>(memory);
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
this->push_back(&items[i]);
|
||||
}
|
||||
|
||||
private:
|
||||
size_t m_chunk_size;
|
||||
Alloc m_alloc;
|
||||
};
|
||||
|
||||
} // namespace kutil
|
||||
19
src/libraries/kutil/spinlock.h
Normal file
19
src/libraries/kutil/spinlock.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
#include <atomic>
|
||||
|
||||
namespace kutil {
|
||||
|
||||
|
||||
class spinlock
|
||||
{
|
||||
public:
|
||||
spinlock() : m_lock(false) {}
|
||||
|
||||
inline void enter() { while (!m_lock.exchange(true)); }
|
||||
inline void leave() { m_lock.store(false); }
|
||||
|
||||
private:
|
||||
std::atomic<bool> m_lock;
|
||||
};
|
||||
|
||||
} // namespace kutil
|
||||
Reference in New Issue
Block a user