mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-21 14:37:50 +00:00
130 lines
3.4 KiB
C++
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__ */
|