genode/os/include/nic/packet_allocator.h
2013-01-10 21:44:47 +01:00

130 lines
3.4 KiB
C++

/*
* \brief Fast-bitmap allocator for NIC-session packet streams
* \author Sebastian Sumpf
* \date 2012-07-30
*
* This allocator can be used with a nic session. It is *not* required though.
*/
/*
* Copyright (C) 2012-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__NIC__PACKET_ALLOCATOR__
#define _INCLUDE__NIC__PACKET_ALLOCATOR__
#include <base/allocator.h>
#include <util/string.h>
namespace Nic {
class Packet_allocator : public Genode::Range_allocator
{
private:
Genode::Allocator *_md_alloc; /* meta-data allocator */
unsigned _block_size; /* network packet size */
Genode::addr_t _base; /* allocation base */
unsigned *_free; /* free list */
int _curr_idx; /* current index in free list */
int _count; /* number of elements */
public:
enum { DEFAULT_PACKET_SIZE = 1600 };
/**
* Constructor
*
* \param md_alloc Meta-data allocator
* \param block_size Size of network packet in stream
*/
Packet_allocator(Genode::Allocator *md_alloc,
unsigned block_size = DEFAULT_PACKET_SIZE)
: _md_alloc(md_alloc), _block_size(block_size), _base(0), _free(0),
_curr_idx(0), _count(0)
{}
~Packet_allocator()
{
if (_free)
_md_alloc->free(_free, sizeof(unsigned) * (_count / 32));
}
/*******************************
** Range-allocator interface **
*******************************/
int add_range(Genode::addr_t base, Genode::size_t size)
{
if (_count)
return -1;
_base = base;
_count = size / _block_size;
_free = (unsigned *)_md_alloc->alloc(sizeof(unsigned) * (_count / 32));
Genode::memset(_free, 0xff, sizeof(unsigned) * (_count / 32));
return 0;
}
Alloc_return alloc_aligned(Genode::size_t size, void **out_addr, int) {
return alloc(size, out_addr) ? Alloc_return::OK
: Alloc_return::RANGE_CONFLICT; }
bool alloc(Genode::size_t size, void **out_addr)
{
int free_cnt = _count / 32;
for (register int i = 0; i < free_cnt; i++) {
if (_free[_curr_idx] != 0) {
unsigned msb = Genode::log2(_free[_curr_idx]);
int elem_idx = (_curr_idx * 32) + msb;
if (elem_idx < _count) {
_free[_curr_idx] ^= (1 << msb);
*out_addr = reinterpret_cast<void *>(_base + (_block_size * elem_idx));
return true;
}
}
_curr_idx = (_curr_idx + 1) % free_cnt;
}
return false;
}
void free(void *addr)
{
Genode::addr_t a = reinterpret_cast<Genode::addr_t>(addr);
int elem_idx = (a - _base) / _block_size;
if (elem_idx >= _count)
return;
_curr_idx = elem_idx / 32;
_free[_curr_idx] |= (1 << (elem_idx % 32));
}
void free(void *addr, Genode::size_t) { free(addr); }
/*********************
** Dummy functions **
*********************/
Genode::size_t overhead(Genode::size_t) { return 0;}
int remove_range(Genode::addr_t, Genode::size_t) { return 0;}
Genode::size_t avail() { return 0; }
bool valid_addr(Genode::addr_t) { return 0; }
Alloc_return alloc_addr(Genode::size_t, Genode::addr_t) {
return Alloc_return(Alloc_return::OUT_OF_METADATA); }
};
};
#endif /* _INCLUDE__NIC__PACKET_ALLOCATOR__ */