/* * \brief Fast-bitmap allocator for packet streams * \author Sebastian Sumpf * \author Stefan Kalkowski * \date 2012-07-30 */ /* * 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__OS__PACKET_ALLOCATOR__ #define _INCLUDE__OS__PACKET_ALLOCATOR__ #include #include namespace Genode { class Packet_allocator; } /** * This allocator is designed to be used as packet allocator for the * packet stream interface. It uses a minimal block size, which is the * granularity packets will be allocated with. As backend, it uses a * simple bit array to manage free, and allocated blocks. */ class Genode::Packet_allocator : public Genode::Range_allocator { private: Allocator *_md_alloc; /* meta-data allocator */ size_t _block_size; /* granularity of packet allocations */ void *_bits; /* memory chunk containing the bits */ Bit_array_base *_array; /* bit array managing available blocks */ addr_t _base; /* allocation base */ addr_t _next; /* next free bit index */ /* * Returns the count of blocks fitting the given size * * The block count returned is aligned to the bit count * of a machine word to fit the needs of the used bit array. */ inline size_t _block_cnt(size_t bytes) { bytes /= _block_size; return bytes - (bytes % (sizeof(addr_t)*8)); } public: /** * Constructor * * \param md_alloc Meta-data allocator * \param block_size Granularity of packets in stream */ Packet_allocator(Allocator *md_alloc, size_t block_size) : _md_alloc(md_alloc), _block_size(block_size), _bits(0), _array(nullptr), _base(0) {} /******************************* ** Range-allocator interface ** *******************************/ int add_range(addr_t base, size_t size) override { if (_base || _array) return -1; _base = base; _bits = _md_alloc->alloc(_block_cnt(size)/8); _array = new (_md_alloc) Bit_array_base(_block_cnt(size), (addr_t*)_bits, true); return 0; } int remove_range(addr_t base, size_t size) override { if (_base != base) return -1; if (_array) destroy(_md_alloc, _array); if (_bits) _md_alloc->free(_bits, _block_cnt(size)/8); return 0; } Alloc_return alloc_aligned(size_t size, void **out_addr, int, addr_t, addr_t) override { return alloc(size, out_addr) ? Alloc_return::OK : Alloc_return::RANGE_CONFLICT; } bool alloc(size_t size, void **out_addr) override { addr_t const cnt = (size % _block_size) ? size / _block_size + 1 : size / _block_size; addr_t max = ~0UL; do { try { /* throws exception if array is accessed outside bounds */ for (addr_t i = _next & ~(cnt - 1); i < max; i += cnt) { if (_array->get(i, cnt)) continue; _array->set(i, cnt); _next = i + cnt; *out_addr = reinterpret_cast(i * _block_size + _base); return true; } } catch (typename Bit_array_base::Invalid_index_access) { } max = _next; _next = 0; } while (max != 0); return false; } void free(void *addr, size_t size) override { addr_t i = (((addr_t)addr) - _base) / _block_size; size_t cnt = (size % _block_size) ? size / _block_size + 1 : size / _block_size; try { _array->clear(i, cnt); } catch(...) { } _next = i; } /************* ** Dummies ** *************/ bool need_size_for_free() const override { return false; } void free(void *addr) override { } size_t overhead(size_t) const override { return 0;} size_t avail() const override { return 0; } bool valid_addr(addr_t) const override { return 0; } Alloc_return alloc_addr(size_t, addr_t) override { return Alloc_return(Alloc_return::OUT_OF_METADATA); } }; #endif /* _INCLUDE__OS__PACKET_ALLOCATOR__ */