genode/repos/base/include/base/slab.h

276 lines
5.7 KiB
C++

/*
* \brief Slab allocator
* \author Norman Feske
* \date 2006-04-18
*/
/*
* Copyright (C) 2006-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _INCLUDE__BASE__SLAB_H_
#define _INCLUDE__BASE__SLAB_H_
#include <base/allocator.h>
#include <base/stdint.h>
namespace Genode {
class Slab;
class Slab_block;
class Slab_entry;
}
/**
* A slab block holds an array of slab entries.
*/
class Genode::Slab_block
{
public:
Slab_block *next; /* next block */
Slab_block *prev; /* previous block */
private:
enum { FREE, USED };
Slab *_slab; /* back reference to slab allocator */
unsigned _avail; /* free entries of this block */
/*
* Each slab block consists of three areas, a fixed-size header
* that contains the member variables declared above, a byte array
* called state table that holds the allocation state for each slab
* entry, and an area holding the actual slab entries. The number
* of state-table elements corresponds to the maximum number of slab
* entries per slab block (the '_num_elem' member variable of the
* Slab allocator).
*/
char _data[]; /* dynamic data (state table and slab entries) */
/*
* Caution! no member variables allowed below this line!
*/
/**
* Return the allocation state of a slab entry
*/
inline bool state(int idx) { return _data[idx]; }
/**
* Set the allocation state of a slab entry
*/
inline void state(int idx, bool state) { _data[idx] = state; }
/**
* Request address of slab entry by its index
*/
Slab_entry *slab_entry(int idx);
/**
* Determine block index of specified slab entry
*/
int slab_entry_idx(Slab_entry *e);
public:
/**
* Constructor
*
* Normally, Slab_blocks are constructed by a Slab allocator
* that specifies itself as constructor argument.
*/
explicit Slab_block(Slab *s = 0) { if (s) slab(s); }
/**
* Configure block to be managed by the specified slab allocator
*/
void slab(Slab *slab);
/**
* Request number of available entries in block
*/
unsigned avail() const { return _avail; }
/**
* Allocate slab entry from block
*/
void *alloc();
/**
* Return a used slab block entry
*/
Slab_entry *first_used_entry();
/**
* These functions are called by Slab_entry.
*/
void inc_avail(Slab_entry *e);
void dec_avail();
/**
* Debug and test hooks
*/
void dump();
int check_bounds();
};
class Genode::Slab_entry
{
private:
Slab_block *_sb;
char _data[];
/*
* Caution! no member variables allowed below this line!
*/
public:
void init() { _sb = 0; }
void occupy(Slab_block *sb)
{
_sb = sb;
_sb->dec_avail();
}
void free()
{
_sb->inc_avail(this);
_sb = 0;
}
void *addr() { return _data; }
/**
* Lookup Slab_entry by given address
*
* The specified address is supposed to point to _data[0].
*/
static Slab_entry *slab_entry(void *addr) {
return (Slab_entry *)((addr_t)addr - sizeof(Slab_entry)); }
};
/**
* Slab allocator
*/
class Genode::Slab : public Allocator
{
private:
size_t _slab_size; /* size of one slab entry */
size_t _block_size; /* size of slab block */
size_t _num_elem; /* number of slab entries per block */
Slab_block *_first_sb; /* first slab block */
Slab_block *_initial_sb; /* initial (static) slab block */
bool _alloc_state; /* indicator for 'currently in service' */
Allocator *_backing_store;
/**
* Allocate and initialize new slab block
*/
Slab_block *_new_slab_block();
public:
inline size_t slab_size() const { return _slab_size; }
inline size_t block_size() const { return _block_size; }
inline size_t num_elem() const { return _num_elem; }
inline size_t entry_size() const { return sizeof(Slab_entry) + _slab_size; }
/**
* Constructor
*
* At construction time, there exists one initial slab
* block that is used for the first couple of allocations,
* especially for the allocation of the second slab
* block.
*/
Slab(size_t slab_size, size_t block_size, Slab_block *initial_sb,
Allocator *backing_store = 0);
/**
* Destructor
*/
~Slab();
/**
* Debug function for dumping the current slab block list
*
* \noapi
*/
void dump_sb_list();
/**
* Remove block from slab block list
*
* \noapi
*/
void remove_sb(Slab_block *sb);
/**
* Insert block into slab block list
*
* \noapi
*/
void insert_sb(Slab_block *sb, Slab_block *at = 0);
/**
* Free slab entry
*/
static void free(void *addr);
/**
* Return a used slab element
*/
void *first_used_elem();
/**
* Return true if number of free slab entries is higher than n
*/
bool num_free_entries_higher_than(int n);
/**
* Define/request backing-store allocator
*
* \noapi
*/
void backing_store(Allocator *bs) { _backing_store = bs; }
/**
* Request backing-store allocator
*
* \noapi
*/
Allocator *backing_store() { return _backing_store; }
/*************************
** Allocator interface **
*************************/
/**
* Allocate slab entry
*
* The 'size' parameter is ignored as only slab entries with
* preconfigured slab-entry size are allocated.
*/
bool alloc(size_t size, void **addr) override;
void free(void *addr, size_t) override { free(addr); }
size_t consumed() const override;
size_t overhead(size_t) const override { return _block_size/_num_elem; }
bool need_size_for_free() const override { return false; }
};
#endif /* _INCLUDE__BASE__SLAB_H_ */