mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [RFC PATCH 0/3] add tlsf memory allocator
@ 2011-12-08 14:03 Antony Pavlov
  2011-12-08 14:03 ` [RFC PATCH 1/3] import TLSF 2.0 from http://tlsf.baisoku.org/tlsf-2.0.zip Antony Pavlov
                   ` (3 more replies)
  0 siblings, 4 replies; 10+ messages in thread
From: Antony Pavlov @ 2011-12-08 14:03 UTC (permalink / raw)
  To: barebox

This patch series adds the tlsf memory allocator to barebox.

TLSF: Two Level Segregated Fit memory allocator implementation.
Written by Matthew Conte (matt@baisoku.org).
Public Domain, no restrictions.

[RFC PATCH 1/3] import TLSF 2.0
[RFC PATCH 2/3] adapt tlsf for barebox
[RFC PATCH 3/3] add tlsf-based malloc implementation

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [RFC PATCH 1/3] import TLSF 2.0 from http://tlsf.baisoku.org/tlsf-2.0.zip
  2011-12-08 14:03 [RFC PATCH 0/3] add tlsf memory allocator Antony Pavlov
@ 2011-12-08 14:03 ` Antony Pavlov
  2011-12-09  9:24   ` Sascha Hauer
  2011-12-08 14:03 ` [RFC PATCH 2/3] adapt tlsf for barebox Antony Pavlov
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 10+ messages in thread
From: Antony Pavlov @ 2011-12-08 14:03 UTC (permalink / raw)
  To: barebox

TLSF: Two Level Segregated Fit memory allocator implementation.
Written by Matthew Conte (matt@baisoku.org).
Public Domain, no restrictions.

Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
---
 common/tlsf.c      |  961 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/tlsf.h     |   52 +++
 include/tlsfbits.h |  180 ++++++++++
 3 files changed, 1193 insertions(+), 0 deletions(-)
 create mode 100644 common/tlsf.c
 create mode 100644 include/tlsf.h
 create mode 100644 include/tlsfbits.h

diff --git a/common/tlsf.c b/common/tlsf.c
new file mode 100644
index 0000000..02dc8d4
--- /dev/null
+++ b/common/tlsf.c
@@ -0,0 +1,961 @@
+#include <assert.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "tlsf.h"
+#include "tlsfbits.h"
+
+/*
+** Constants.
+*/
+
+/* Public constants: may be modified. */
+enum tlsf_public
+{
+	/* log2 of number of linear subdivisions of block sizes. */
+	SL_INDEX_COUNT_LOG2 = 5,
+};
+
+/* Private constants: do not modify. */
+enum tlsf_private
+{
+#if defined (TLSF_64BIT)
+	/* All allocation sizes and addresses are aligned to 8 bytes. */
+	ALIGN_SIZE_LOG2 = 3,
+#else
+	/* All allocation sizes and addresses are aligned to 4 bytes. */
+	ALIGN_SIZE_LOG2 = 2,
+#endif
+	ALIGN_SIZE = (1 << ALIGN_SIZE_LOG2),
+
+	/*
+	** We support allocations of sizes up to (1 << FL_INDEX_MAX) bits.
+	** However, because we linearly subdivide the second-level lists, and
+	** our minimum size granularity is 4 bytes, it doesn't make sense to
+	** create first-level lists for sizes smaller than SL_INDEX_COUNT * 4,
+	** or (1 << (SL_INDEX_COUNT_LOG2 + 2)) bytes, as there we will be
+	** trying to split size ranges into more slots than we have available.
+	** Instead, we calculate the minimum threshold size, and place all
+	** blocks below that size into the 0th first-level list.
+	*/
+
+#if defined (TLSF_64BIT)
+	/*
+	** TODO: We can increase this to support larger sizes, at the expense
+	** of more overhead in the TLSF structure.
+	*/
+	FL_INDEX_MAX = 32,
+#else
+	FL_INDEX_MAX = 30,
+#endif
+	SL_INDEX_COUNT = (1 << SL_INDEX_COUNT_LOG2),
+	FL_INDEX_SHIFT = (SL_INDEX_COUNT_LOG2 + ALIGN_SIZE_LOG2),
+	FL_INDEX_COUNT = (FL_INDEX_MAX - FL_INDEX_SHIFT + 1),
+
+	SMALL_BLOCK_SIZE = (1 << FL_INDEX_SHIFT),
+};
+
+/*
+** Cast and min/max macros.
+*/
+
+#define tlsf_cast(t, exp)	((t) (exp))
+#define tlsf_min(a, b)		((a) < (b) ? (a) : (b))
+#define tlsf_max(a, b)		((a) > (b) ? (a) : (b))
+
+/*
+** Set assert macro, if it has not been provided by the user.
+*/
+#if !defined (tlsf_assert)
+#define tlsf_assert assert
+#endif
+
+/*
+** Static assertion mechanism.
+*/
+
+#define _tlsf_glue2(x, y) x ## y
+#define _tlsf_glue(x, y) _tlsf_glue2(x, y)
+#define tlsf_static_assert(exp) \
+	typedef char _tlsf_glue(static_assert, __LINE__) [(exp) ? 1 : -1]
+
+/* This code has been tested on 32- and 64-bit (LP/LLP) architectures. */
+tlsf_static_assert(sizeof(int) * CHAR_BIT == 32);
+tlsf_static_assert(sizeof(size_t) * CHAR_BIT >= 32);
+tlsf_static_assert(sizeof(size_t) * CHAR_BIT <= 64);
+
+/* SL_INDEX_COUNT must be <= number of bits in sl_bitmap's storage type. */
+tlsf_static_assert(sizeof(unsigned int) * CHAR_BIT >= SL_INDEX_COUNT);
+
+/* Ensure we've properly tuned our sizes. */
+tlsf_static_assert(ALIGN_SIZE == SMALL_BLOCK_SIZE / SL_INDEX_COUNT);
+
+/*
+** Data structures and associated constants.
+*/
+
+/*
+** Block header structure.
+**
+** There are several implementation subtleties involved:
+** - The prev_phys_block field is only valid if the previous block is free.
+** - The prev_phys_block field is actually stored at the end of the
+**   previous block. It appears at the beginning of this structure only to
+**   simplify the implementation.
+** - The next_free / prev_free fields are only valid if the block is free.
+*/
+typedef struct block_header_t
+{
+	/* Points to the previous physical block. */
+	struct block_header_t* prev_phys_block;
+
+	/* The size of this block, excluding the block header. */
+	size_t size;
+
+	/* Next and previous free blocks. */
+	struct block_header_t* next_free;
+	struct block_header_t* prev_free;
+} block_header_t;
+
+/*
+** Since block sizes are always at least a multiple of 4, the two least
+** significant bits of the size field are used to store the block status:
+** - bit 0: whether block is busy or free
+** - bit 1: whether previous block is busy or free
+*/
+static const size_t block_header_free_bit = 1 << 0;
+static const size_t block_header_prev_free_bit = 1 << 1;
+
+/*
+** The size of the block header exposed to used blocks is the size field.
+** The prev_phys_block field is stored *inside* the previous free block.
+*/
+static const size_t block_header_overhead = sizeof(size_t);
+
+/* User data starts directly after the size field in a used block. */
+static const size_t block_start_offset =
+	offsetof(block_header_t, size) + sizeof(size_t);
+
+/*
+** A free block must be large enough to store its header minus the size of
+** the prev_phys_block field, and no larger than the number of addressable
+** bits for FL_INDEX.
+*/
+static const size_t block_size_min = 
+	sizeof(block_header_t) - sizeof(block_header_t*);
+static const size_t block_size_max = tlsf_cast(size_t, 1) << FL_INDEX_MAX;
+
+
+/* The TLSF pool structure. */
+typedef struct pool_t
+{
+	/* Empty lists point at this block to indicate they are free. */
+	block_header_t block_null;
+
+	/* Bitmaps for free lists. */
+	unsigned int fl_bitmap;
+	unsigned int sl_bitmap[FL_INDEX_COUNT];
+
+	/* Head of free lists. */
+	block_header_t* blocks[FL_INDEX_COUNT][SL_INDEX_COUNT];
+} pool_t;
+
+/* A type used for casting when doing pointer arithmetic. */
+typedef ptrdiff_t tlsfptr_t;
+
+/*
+** block_header_t member functions.
+*/
+
+static size_t block_size(const block_header_t* block)
+{
+	return block->size & ~(block_header_free_bit | block_header_prev_free_bit);
+}
+
+static void block_set_size(block_header_t* block, size_t size)
+{
+	const size_t oldsize = block->size;
+	block->size = size | (oldsize & (block_header_free_bit | block_header_prev_free_bit));
+}
+
+static int block_is_last(const block_header_t* block)
+{
+	return 0 == block_size(block);
+}
+
+static int block_is_free(const block_header_t* block)
+{
+	return tlsf_cast(int, block->size & block_header_free_bit);
+}
+
+static void block_set_free(block_header_t* block)
+{
+	block->size |= block_header_free_bit;
+}
+
+static void block_set_used(block_header_t* block)
+{
+	block->size &= ~block_header_free_bit;
+}
+
+static int block_is_prev_free(const block_header_t* block)
+{
+	return tlsf_cast(int, block->size & block_header_prev_free_bit);
+}
+
+static void block_set_prev_free(block_header_t* block)
+{
+	block->size |= block_header_prev_free_bit;
+}
+
+static void block_set_prev_used(block_header_t* block)
+{
+	block->size &= ~block_header_prev_free_bit;
+}
+
+static block_header_t* block_from_ptr(const void* ptr)
+{
+	return tlsf_cast(block_header_t*,
+		tlsf_cast(unsigned char*, ptr) - block_start_offset);
+}
+
+static void* block_to_ptr(const block_header_t* block)
+{
+	return tlsf_cast(void*,
+		tlsf_cast(unsigned char*, block) + block_start_offset);
+}
+
+/* Return location of next block after block of given size. */
+static block_header_t* offset_to_block(const void* ptr, size_t size)
+{
+	return tlsf_cast(block_header_t*, tlsf_cast(tlsfptr_t, ptr) + size);
+}
+
+/* Return location of previous block. */
+static block_header_t* block_prev(const block_header_t* block)
+{
+	return block->prev_phys_block;
+}
+
+/* Return location of next existing block. */
+static block_header_t* block_next(const block_header_t* block)
+{
+	block_header_t* next = offset_to_block(block_to_ptr(block),
+		block_size(block) - block_header_overhead);
+	tlsf_assert(!block_is_last(block));
+	return next;
+}
+
+/* Link a new block with its physical neighbor, return the neighbor. */
+static block_header_t* block_link_next(block_header_t* block)
+{
+	block_header_t* next = block_next(block);
+	next->prev_phys_block = block;
+	return next;
+}
+
+static void block_mark_as_free(block_header_t* block)
+{
+	/* Link the block to the next block, first. */
+	block_header_t* next = block_link_next(block);
+	block_set_prev_free(next);
+	block_set_free(block);
+}
+
+static void block_mark_as_used(block_header_t* block)
+{
+	block_header_t* next = block_next(block);
+	block_set_prev_used(next);
+	block_set_used(block);
+}
+
+static size_t align_up(size_t x, size_t align)
+{
+	tlsf_assert(0 == (align & (align - 1)) && "must align to a power of two");
+	return (x + (align - 1)) & ~(align - 1);
+}
+
+static size_t align_down(size_t x, size_t align)
+{
+	tlsf_assert(0 == (align & (align - 1)) && "must align to a power of two");
+	return x - (x & (align - 1));
+}
+
+static void* align_ptr(const void* ptr, size_t align)
+{
+	const tlsfptr_t aligned =
+		(tlsf_cast(tlsfptr_t, ptr) + (align - 1)) & ~(align - 1);
+	tlsf_assert(0 == (align & (align - 1)) && "must align to a power of two");
+	return tlsf_cast(void*, aligned);
+}
+
+/*
+** Adjust an allocation size to be aligned to word size, and no smaller
+** than internal minimum.
+*/
+static size_t adjust_request_size(size_t size, size_t align)
+{
+	size_t adjust = 0;
+	if (size && size < block_size_max)
+	{
+		const size_t aligned = align_up(size, align);
+		adjust = tlsf_max(aligned, block_size_min);
+	}
+	return adjust;
+}
+
+/*
+** TLSF utility functions. In most cases, these are direct translations of
+** the documentation found in the white paper.
+*/
+
+static void mapping_insert(size_t size, int* fli, int* sli)
+{
+	int fl, sl;
+	if (size < SMALL_BLOCK_SIZE)
+	{
+		/* Store small blocks in first list. */
+		fl = 0;
+		sl = tlsf_cast(int, size) / (SMALL_BLOCK_SIZE / SL_INDEX_COUNT);
+	}
+	else
+	{
+		fl = tlsf_fls_sizet(size);
+		sl = tlsf_cast(int, size >> (fl - SL_INDEX_COUNT_LOG2)) ^ (1 << SL_INDEX_COUNT_LOG2);
+		fl -= (FL_INDEX_SHIFT - 1);
+	}
+	*fli = fl;
+	*sli = sl;
+}
+
+/* This version rounds up to the next block size (for allocations) */
+static void mapping_search(size_t size, int* fli, int* sli)
+{
+	if (size >= (1 << SL_INDEX_COUNT_LOG2))
+	{
+		const size_t round = (1 << (tlsf_fls_sizet(size) - SL_INDEX_COUNT_LOG2)) - 1;
+		size += round;
+	}
+	mapping_insert(size, fli, sli);
+}
+
+static block_header_t* search_suitable_block(pool_t* pool, int* fli, int* sli)
+{
+	int fl = *fli;
+	int sl = *sli;
+
+	/*
+	** First, search for a block in the list associated with the given
+	** fl/sl index.
+	*/
+	unsigned int sl_map = pool->sl_bitmap[fl] & (~0 << sl);
+	if (!sl_map)
+	{
+		/* No block exists. Search in the next largest first-level list. */
+		const unsigned int fl_map = pool->fl_bitmap & (~0 << (fl + 1));
+		if (!fl_map)
+		{
+			/* No free blocks available, memory has been exhausted. */
+			return 0;
+		}
+
+		fl = tlsf_ffs(fl_map);
+		*fli = fl;
+		sl_map = pool->sl_bitmap[fl];
+	}
+	tlsf_assert(sl_map && "internal error - second level bitmap is null");
+	sl = tlsf_ffs(sl_map);
+	*sli = sl;
+
+	/* Return the first block in the free list. */
+	return pool->blocks[fl][sl];
+}
+
+/* Remove a free block from the free list.*/
+static void remove_free_block(pool_t* pool, block_header_t* block, int fl, int sl)
+{
+	block_header_t* prev = block->prev_free;
+	block_header_t* next = block->next_free;
+	tlsf_assert(prev && "prev_free field can not be null");
+	tlsf_assert(next && "next_free field can not be null");
+	next->prev_free = prev;
+	prev->next_free = next;
+
+	/* If this block is the head of the free list, set new head. */
+	if (pool->blocks[fl][sl] == block)
+	{
+		pool->blocks[fl][sl] = next;
+
+		/* If the new head is null, clear the bitmap. */
+		if (next == &pool->block_null)
+		{
+			pool->sl_bitmap[fl] &= ~(1 << sl);
+
+			/* If the second bitmap is now empty, clear the fl bitmap. */
+			if (!pool->sl_bitmap[fl])
+			{
+				pool->fl_bitmap &= ~(1 << fl);
+			}
+		}
+	}
+}
+
+/* Insert a free block into the free block list. */
+static void insert_free_block(pool_t* pool, block_header_t* block, int fl, int sl)
+{
+	block_header_t* current = pool->blocks[fl][sl];
+	tlsf_assert(current && "free list cannot have a null entry");
+	tlsf_assert(block && "cannot insert a null entry into the free list");
+	block->next_free = current;
+	block->prev_free = &pool->block_null;
+	current->prev_free = block;
+
+	tlsf_assert(block_to_ptr(block) == align_ptr(block_to_ptr(block), ALIGN_SIZE)
+		&& "block not aligned properly");
+	/*
+	** Insert the new block at the head of the list, and mark the first-
+	** and second-level bitmaps appropriately.
+	*/
+	pool->blocks[fl][sl] = block;
+	pool->fl_bitmap |= (1 << fl);
+	pool->sl_bitmap[fl] |= (1 << sl);
+}
+
+/* Remove a given block from the free list. */
+static void block_remove(pool_t* pool, block_header_t* block)
+{
+	int fl, sl;
+	mapping_insert(block_size(block), &fl, &sl);
+	remove_free_block(pool, block, fl, sl);
+}
+
+/* Insert a given block into the free list. */
+static void block_insert(pool_t* pool, block_header_t* block)
+{
+	int fl, sl;
+	mapping_insert(block_size(block), &fl, &sl);
+	insert_free_block(pool, block, fl, sl);
+}
+
+static int block_can_split(block_header_t* block, size_t size)
+{
+	return block_size(block) >= sizeof(block_header_t) + size;
+}
+
+/* Split a block into two, the second of which is free. */
+static block_header_t* block_split(block_header_t* block, size_t size)
+{
+	/* Calculate the amount of space left in the remaining block. */
+	block_header_t* remaining =
+		offset_to_block(block_to_ptr(block), size - block_header_overhead);
+
+	const size_t remain_size = block_size(block) - (size + block_header_overhead);
+
+	tlsf_assert(block_to_ptr(remaining) == align_ptr(block_to_ptr(remaining), ALIGN_SIZE)
+		&& "remaining block not aligned properly");
+
+	tlsf_assert(block_size(block) == remain_size + size + block_header_overhead);
+	block_set_size(remaining, remain_size);
+	tlsf_assert(block_size(remaining) >= block_size_min && "block split with invalid size");
+
+	block_set_size(block, size);
+	block_mark_as_free(remaining);
+
+	return remaining;
+}
+
+/* Absorb a free block's storage into an adjacent previous free block. */
+static block_header_t* block_absorb(block_header_t* prev, block_header_t* block)
+{
+	tlsf_assert(!block_is_last(prev) && "previous block can't be last!");
+	/* Note: Leaves flags untouched. */
+	prev->size += block_size(block) + block_header_overhead;
+	block_link_next(prev);
+	return prev;
+}
+
+/* Merge a just-freed block with an adjacent previous free block. */
+static block_header_t* block_merge_prev(pool_t* pool, block_header_t* block)
+{
+	if (block_is_prev_free(block))
+	{
+		block_header_t* prev = block_prev(block);
+		tlsf_assert(prev && "prev physical block can't be null");
+		tlsf_assert(block_is_free(prev) && "prev block is not free though marked as such");
+		block_remove(pool, prev);
+		block = block_absorb(prev, block);
+	}
+
+	return block;
+}
+
+/* Merge a just-freed block with an adjacent free block. */
+static block_header_t* block_merge_next(pool_t* pool, block_header_t* block)
+{
+	block_header_t* next = block_next(block);
+	tlsf_assert(next && "next physical block can't be null");
+
+	if (block_is_free(next))
+	{
+		tlsf_assert(!block_is_last(block) && "previous block can't be last!");
+		block_remove(pool, next);
+		block = block_absorb(block, next);
+	}
+
+	return block;
+}
+
+/* Trim any trailing block space off the end of a block, return to pool. */
+static void block_trim_free(pool_t* pool, block_header_t* block, size_t size)
+{
+	tlsf_assert(block_is_free(block) && "block must be free");
+	if (block_can_split(block, size))
+	{
+		block_header_t* remaining_block = block_split(block, size);
+		block_link_next(block);
+		block_set_prev_free(remaining_block);
+		block_insert(pool, remaining_block);
+	}
+}
+
+/* Trim any trailing block space off the end of a used block, return to pool. */
+static void block_trim_used(pool_t* pool, block_header_t* block, size_t size)
+{
+	tlsf_assert(!block_is_free(block) && "block must be used");
+	if (block_can_split(block, size))
+	{
+		/* If the next block is free, we must coalesce. */
+		block_header_t* remaining_block = block_split(block, size);
+		block_set_prev_used(remaining_block);
+
+		remaining_block = block_merge_next(pool, remaining_block);
+		block_insert(pool, remaining_block);
+	}
+}
+
+static block_header_t* block_trim_free_leading(pool_t* pool, block_header_t* block, size_t size)
+{
+	block_header_t* remaining_block = block;
+	if (block_can_split(block, size))
+	{
+		/* We want the 2nd block. */
+		remaining_block = block_split(block, size - block_header_overhead);
+		block_set_prev_free(remaining_block);
+
+		block_link_next(block);
+		block_insert(pool, block);
+	}
+
+	return remaining_block;
+}
+
+static block_header_t* block_locate_free(pool_t* pool, size_t size)
+{
+	int fl = 0, sl = 0;
+	block_header_t* block = 0;
+
+	if (size)
+	{
+		mapping_search(size, &fl, &sl);
+		block = search_suitable_block(pool, &fl, &sl);
+	}
+
+	if (block)
+	{
+		tlsf_assert(block_size(block) >= size);
+		remove_free_block(pool, block, fl, sl);
+	}
+
+	return block;
+}
+
+static void* block_prepare_used(pool_t* pool, block_header_t* block, size_t size)
+{
+	void* p = 0;
+	if (block)
+	{
+		block_trim_free(pool, block, size);
+		block_mark_as_used(block);
+		p = block_to_ptr(block);
+	}
+	return p;
+}
+
+/* Clear structure and point all empty lists at the null block. */
+static void pool_construct(pool_t* pool)
+{
+	int i, j;
+
+	pool->block_null.next_free = &pool->block_null;
+	pool->block_null.prev_free = &pool->block_null;
+
+	pool->fl_bitmap = 0;
+	for (i = 0; i < FL_INDEX_COUNT; ++i)
+	{
+		pool->sl_bitmap[i] = 0;
+		for (j = 0; j < SL_INDEX_COUNT; ++j)
+		{
+			pool->blocks[i][j] = &pool->block_null;
+		}
+	}
+}
+
+/*
+** Debugging utilities.
+*/
+
+typedef struct integrity_t
+{
+	int prev_status;
+	int status;
+} integrity_t;
+
+#define tlsf_insist(x) { tlsf_assert(x); if (!(x)) { status--; } }
+
+static void integrity_walker(void* ptr, size_t size, int used, void* user)
+{
+	block_header_t* block = block_from_ptr(ptr);
+	integrity_t* integ = tlsf_cast(integrity_t*, user);
+	const int this_prev_status = block_is_prev_free(block) ? 1 : 0;
+	const int this_status = block_is_free(block) ? 1 : 0;
+	const size_t this_block_size = block_size(block);
+
+	int status = 0;
+	tlsf_insist(integ->prev_status == this_prev_status && "prev status incorrect");
+	tlsf_insist(size == this_block_size && "block size incorrect");
+
+	integ->prev_status = this_status;
+	integ->status += status;
+}
+
+int tlsf_check_heap(tlsf_pool tlsf)
+{
+	int i, j;
+
+	pool_t* pool = tlsf_cast(pool_t*, tlsf);
+	int status = 0;
+
+	/* Check that the blocks are physically correct. */
+	integrity_t integ = { 0, 0 };
+	tlsf_walk_heap(tlsf, integrity_walker, &integ);
+	status = integ.status;
+
+	/* Check that the free lists and bitmaps are accurate. */
+	for (i = 0; i < FL_INDEX_COUNT; ++i)
+	{
+		for (j = 0; j < SL_INDEX_COUNT; ++j)
+		{
+			const int fl_map = pool->fl_bitmap & (1 << i);
+			const int sl_list = pool->sl_bitmap[i];
+			const int sl_map = sl_list & (1 << j);
+			const block_header_t* block = pool->blocks[i][j];
+
+			/* Check that first- and second-level lists agree. */
+			if (!fl_map)
+			{
+				tlsf_insist(!sl_map && "second-level map must be null");
+			}
+
+			if (!sl_map)
+			{
+				tlsf_insist(block == &pool->block_null && "block list must be null");
+				continue;
+			}
+
+			/* Check that there is at least one free block. */
+			tlsf_insist(sl_list && "no free blocks in second-level map");
+			tlsf_insist(block != &pool->block_null && "block should not be null");
+
+			while (block != &pool->block_null)
+			{
+				int fli, sli;
+				tlsf_insist(block_is_free(block) && "block should be free");
+				tlsf_insist(!block_is_prev_free(block) && "blocks should have coalesced");
+				tlsf_insist(!block_is_free(block_next(block)) && "blocks should have coalesced");
+				tlsf_insist(block_is_prev_free(block_next(block)) && "block should be free");
+				tlsf_insist(block_size(block) >= block_size_min && "block not minimum size");
+
+				mapping_insert(block_size(block), &fli, &sli);
+				tlsf_insist(fli == i && sli == j && "block size indexed in wrong list");
+				block = block->next_free;
+			}
+		}
+	}
+
+	return status;
+}
+
+#undef tlsf_insist
+
+static void default_walker(void* ptr, size_t size, int used, void* user)
+{
+	(void)user;
+	printf("\t%p %s size: %x (%p)\n", ptr, used ? "used" : "free", (unsigned int)size, block_from_ptr(ptr));
+}
+
+void tlsf_walk_heap(tlsf_pool pool, tlsf_walker walker, void* user)
+{
+	tlsf_walker heap_walker = walker ? walker : default_walker;
+	block_header_t* block =
+		offset_to_block(pool, sizeof(pool_t) - block_header_overhead);
+
+	while (block && !block_is_last(block))
+	{
+		heap_walker(
+			block_to_ptr(block),
+			block_size(block),
+			!block_is_free(block),
+			user);
+		block = block_next(block);
+	}
+}
+
+size_t tlsf_block_size(void* ptr)
+{
+	size_t size = 0;
+	if (ptr)
+	{
+		const block_header_t* block = block_from_ptr(ptr);
+		size = block_size(block);
+	}
+	return size;
+}
+
+/*
+** Overhead of the TLSF structures in a given memory block passed to
+** tlsf_create, equal to the size of a pool_t plus overhead of the initial
+** free block and the sentinel block.
+*/
+size_t tlsf_overhead()
+{
+	const size_t pool_overhead = sizeof(pool_t) + 2 * block_header_overhead;
+	return pool_overhead;
+}
+
+/*
+** TLSF main interface. Right out of the white paper.
+*/
+
+tlsf_pool tlsf_create(void* mem, size_t bytes)
+{
+	block_header_t* block;
+	block_header_t* next;
+
+	const size_t pool_overhead = tlsf_overhead();
+	const size_t pool_bytes = align_down(bytes - pool_overhead, ALIGN_SIZE);
+	pool_t* pool = tlsf_cast(pool_t*, mem);
+
+#if _DEBUG
+	/* Verify ffs/fls work properly. */
+	int rv = 0;
+	rv += (tlsf_ffs(0) == -1) ? 0 : 0x1;
+	rv += (tlsf_fls(0) == -1) ? 0 : 0x2;
+	rv += (tlsf_ffs(1) == 0) ? 0 : 0x4;
+	rv += (tlsf_fls(1) == 0) ? 0 : 0x8;
+	rv += (tlsf_ffs(0x80000000) == 31) ? 0 : 0x10;
+	rv += (tlsf_ffs(0x80008000) == 15) ? 0 : 0x20;
+	rv += (tlsf_fls(0x80000008) == 31) ? 0 : 0x40;
+	rv += (tlsf_fls(0x7FFFFFFF) == 30) ? 0 : 0x80;
+
+#if defined (TLSF_64BIT)
+	rv += (tlsf_fls_sizet(0x80000000) == 31) ? 0 : 0x100;
+	rv += (tlsf_fls_sizet(0x100000000) == 32) ? 0 : 0x200;
+	rv += (tlsf_fls_sizet(0xffffffffffffffff) == 63) ? 0 : 0x400; 
+	if (rv)
+	{
+		printf("tlsf_create: %x ffs/fls tests failed!\n", rv);
+		return 0;
+	}
+#endif
+#endif
+
+	if (pool_bytes < block_size_min || pool_bytes > block_size_max)
+	{
+#if defined (TLSF_64BIT)
+		printf("tlsf_create: Pool size must be at least %d bytes.\n",
+			(unsigned int)(pool_overhead + block_size_min));
+#else
+		printf("tlsf_create: Pool size must be between %u and %u bytes.\n", 
+			(unsigned int)(pool_overhead + block_size_min),
+			(unsigned int)(pool_overhead + block_size_max));
+#endif
+		return 0;
+	}
+
+	/* Construct a valid pool object. */
+	pool_construct(pool);
+
+	/*
+	** Create the main free block. Offset the start of the block slightly
+	** so that the prev_phys_block field falls inside of the pool
+	** structure - it will never be used.
+	*/
+	block = offset_to_block(
+		tlsf_cast(void*, pool), sizeof(pool_t) - block_header_overhead);
+	block_set_size(block, pool_bytes);
+	block_set_free(block);
+	block_set_prev_used(block);
+	block_insert(pool, block);
+
+	/* Split the block to create a zero-size pool sentinel block. */
+	next = block_link_next(block);
+	block_set_size(next, 0);
+	block_set_used(next);
+	block_set_prev_free(next);
+
+	return tlsf_cast(tlsf_pool, pool);
+}
+
+void tlsf_destroy(tlsf_pool pool)
+{
+	/* Nothing to do. */
+	pool = pool;
+}
+
+void* tlsf_malloc(tlsf_pool tlsf, size_t size)
+{
+	pool_t* pool = tlsf_cast(pool_t*, tlsf);
+	const size_t adjust = adjust_request_size(size, ALIGN_SIZE);
+	block_header_t* block = block_locate_free(pool, adjust);
+	return block_prepare_used(pool, block, adjust);
+}
+
+void* tlsf_memalign(tlsf_pool tlsf, size_t align, size_t size)
+{
+	pool_t* pool = tlsf_cast(pool_t*, tlsf);
+	const size_t adjust = adjust_request_size(size, ALIGN_SIZE);
+
+	/*
+	** We must allocate an additional minimum block size bytes so that if
+	** our free block will leave an alignment gap which is smaller, we can
+	** trim a leading free block and release it back to the heap. We must
+	** do this because the previous physical block is in use, therefore
+	** the prev_phys_block field is not valid, and we can't simply adjust
+	** the size of that block.
+	*/
+	const size_t gap_minimum = sizeof(block_header_t);
+	const size_t size_with_gap = adjust_request_size(adjust + align + gap_minimum, align);
+
+	/* If alignment is less than or equals base alignment, we're done. */
+	const size_t aligned_size = (align <= ALIGN_SIZE) ? adjust : size_with_gap;
+
+	block_header_t* block = block_locate_free(pool, aligned_size);
+
+	/* This can't be a static assert. */
+	tlsf_assert(sizeof(block_header_t) == block_size_min + block_header_overhead);
+
+	if (block)
+	{
+		void* ptr = block_to_ptr(block);
+		void* aligned = align_ptr(ptr, align);
+		size_t gap = tlsf_cast(size_t,
+			tlsf_cast(tlsfptr_t, aligned) - tlsf_cast(tlsfptr_t, ptr));
+
+		/* If gap size is too small, offset to next aligned boundary. */
+		if (gap && gap < gap_minimum)
+		{
+			const size_t gap_remain = gap_minimum - gap;
+			const size_t offset = tlsf_max(gap_remain, align);
+			const void* next_aligned = tlsf_cast(void*,
+				tlsf_cast(tlsfptr_t, aligned) + offset);
+
+			aligned = align_ptr(next_aligned, align);
+			gap = tlsf_cast(size_t,
+				tlsf_cast(tlsfptr_t, aligned) - tlsf_cast(tlsfptr_t, ptr));
+		}
+
+		if (gap)
+		{
+			tlsf_assert(gap >= gap_minimum && "gap size too small");
+			block = block_trim_free_leading(pool, block, gap);
+		}
+	}
+
+	return block_prepare_used(pool, block, adjust);
+}
+
+void tlsf_free(tlsf_pool tlsf, void* ptr)
+{
+	/* Don't attempt to free a NULL pointer. */
+	if (ptr)
+	{
+		pool_t* pool = tlsf_cast(pool_t*, tlsf);
+		block_header_t* block = block_from_ptr(ptr);
+		block_mark_as_free(block);
+		block = block_merge_prev(pool, block);
+		block = block_merge_next(pool, block);
+		block_insert(pool, block);
+	}
+}
+
+/*
+** The TLSF block information provides us with enough information to
+** provide a reasonably intelligent implementation of realloc, growing or
+** shrinking the currently allocated block as required.
+**
+** This routine handles the somewhat esoteric edge cases of realloc:
+** - a non-zero size with a null pointer will behave like malloc
+** - a zero size with a non-null pointer will behave like free
+** - a request that cannot be satisfied will leave the original buffer
+**   untouched
+** - an extended buffer size will leave the newly-allocated area with
+**   contents undefined
+*/
+void* tlsf_realloc(tlsf_pool tlsf, void* ptr, size_t size)
+{
+	pool_t* pool = tlsf_cast(pool_t*, tlsf);
+	void* p = 0;
+
+	/* Zero-size requests are treated as free. */
+	if (ptr && size == 0)
+	{
+		tlsf_free(tlsf, ptr);
+	}
+	/* Requests with NULL pointers are treated as malloc. */
+	else if (!ptr)
+	{
+		p = tlsf_malloc(tlsf, size);
+	}
+	else
+	{
+		block_header_t* block = block_from_ptr(ptr);
+		block_header_t* next = block_next(block);
+
+		const size_t cursize = block_size(block);
+		const size_t combined = cursize + block_size(next) + block_header_overhead;
+		const size_t adjust = adjust_request_size(size, ALIGN_SIZE);
+
+		/*
+		** If the next block is used, or when combined with the current
+		** block, does not offer enough space, we must reallocate and copy.
+		*/
+		if (adjust > cursize && (!block_is_free(next) || adjust > combined))
+		{
+			p = tlsf_malloc(tlsf, size);
+			if (p)
+			{
+				const size_t minsize = tlsf_min(cursize, size);
+				memcpy(p, ptr, minsize);
+				tlsf_free(tlsf, ptr);
+			}
+		}
+		else
+		{
+			/* Do we need to expand to the next block? */
+			if (adjust > cursize)
+			{
+				block_merge_next(pool, block);
+				block_mark_as_used(block);
+			}
+
+			/* Trim the resulting block and return the original pointer. */
+			block_trim_used(pool, block, adjust);
+			p = ptr;
+		}
+	}
+
+	return p;
+}
diff --git a/include/tlsf.h b/include/tlsf.h
new file mode 100644
index 0000000..de7f90b
--- /dev/null
+++ b/include/tlsf.h
@@ -0,0 +1,52 @@
+#ifndef INCLUDED_tlsf
+#define INCLUDED_tlsf
+
+/*
+** Two Level Segregated Fit memory allocator, version 1.9.
+** Written by Matthew Conte, and placed in the Public Domain.
+**	http://tlsf.baisoku.org
+**
+** Based on the original documentation by Miguel Masmano:
+**	http://rtportal.upv.es/rtmalloc/allocators/tlsf/index.shtml
+**
+** Please see the accompanying Readme.txt for implementation
+** notes and caveats.
+**
+** This implementation was written to the specification
+** of the document, therefore no GPL restrictions apply.
+*/
+
+#include <stddef.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* Create/destroy a memory pool. */
+typedef void* tlsf_pool;
+tlsf_pool tlsf_create(void* mem, size_t bytes);
+void tlsf_destroy(tlsf_pool pool);
+
+/* malloc/memalign/realloc/free replacements. */
+void* tlsf_malloc(tlsf_pool pool, size_t bytes);
+void* tlsf_memalign(tlsf_pool pool, size_t align, size_t bytes);
+void* tlsf_realloc(tlsf_pool pool, void* ptr, size_t size);
+void tlsf_free(tlsf_pool pool, void* ptr);
+
+/* Debugging. */
+typedef void (*tlsf_walker)(void* ptr, size_t size, int used, void* user);
+void tlsf_walk_heap(tlsf_pool pool, tlsf_walker walker, void* user);
+/* Returns nonzero if heap check fails. */
+int tlsf_check_heap(tlsf_pool pool);
+
+/* Returns internal block size, not original request size */
+size_t tlsf_block_size(void* ptr);
+
+/* Overhead of per-pool internal structures. */
+size_t tlsf_overhead();
+
+#if defined(__cplusplus)
+};
+#endif
+
+#endif
diff --git a/include/tlsfbits.h b/include/tlsfbits.h
new file mode 100644
index 0000000..3e5c82a
--- /dev/null
+++ b/include/tlsfbits.h
@@ -0,0 +1,180 @@
+#ifndef INCLUDED_tlsfbits
+#define INCLUDED_tlsfbits
+
+#if defined(__cplusplus)
+#define tlsf_decl inline
+#else
+#define tlsf_decl static
+#endif
+
+/*
+** Architecture-specific bit manipulation routines.
+**
+** TLSF achieves O(1) cost for malloc and free operations by limiting
+** the search for a free block to a free list of guaranteed size
+** adequate to fulfill the request, combined with efficient free list
+** queries using bitmasks and architecture-specific bit-manipulation
+** routines.
+**
+** Most modern processors provide instructions to count leading zeroes
+** in a word, find the lowest and highest set bit, etc. These
+** specific implementations will be used when available, falling back
+** to a reasonably efficient generic implementation.
+**
+** NOTE: TLSF spec relies on ffs/fls returning value 0..31.
+** ffs/fls return 1-32 by default, returning 0 for error.
+*/
+
+/*
+** Detect whether or not we are building for a 32- or 64-bit (LP/LLP)
+** architecture. There is no reliable portable method at compile-time.
+*/
+#if defined (__alpha__) || defined (__ia64__) || defined (__x86_64__) \
+	|| defined (_WIN64) || defined (__LP64__) || defined (__LLP64__)
+#define TLSF_64BIT
+#endif
+
+/*
+** gcc 3.4 and above have builtin support, specialized for architecture.
+** Some compilers masquerade as gcc; patchlevel test filters them out.
+*/
+#if defined (__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) \
+	&& defined (__GNUC_PATCHLEVEL__)
+
+tlsf_decl int tlsf_ffs(unsigned int word)
+{
+	return __builtin_ffs(word) - 1;
+}
+
+tlsf_decl int tlsf_fls(unsigned int word)
+{
+	const int bit = word ? 32 - __builtin_clz(word) : 0;
+	return bit - 1;
+}
+
+#elif defined (_MSC_VER) && defined (_M_IX86) && (_MSC_VER >= 1400)
+/* Microsoft Visual C++ 2005 support on x86 architectures. */
+
+#include <intrin.h>
+
+#pragma intrinsic(_BitScanReverse)
+#pragma intrinsic(_BitScanForward)
+
+tlsf_decl int tlsf_fls(unsigned int word)
+{
+	unsigned long index;
+	return _BitScanReverse(&index, word) ? index : -1;
+}
+
+tlsf_decl int tlsf_ffs(unsigned int word)
+{
+	unsigned long index;
+	return _BitScanForward(&index, word) ? index : -1;
+}
+
+#elif defined (_MSC_VER) && defined (_M_PPC)
+/* Microsoft Visual C++ support on PowerPC architectures. */
+
+#include <ppcintrinsics.h>
+
+tlsf_decl int tlsf_fls(unsigned int word)
+{
+	const int bit = 32 - _CountLeadingZeros(word);
+	return bit - 1;
+}
+
+tlsf_decl int tlsf_ffs(unsigned int word)
+{
+	const unsigned int reverse = word & (~word + 1);
+	const int bit = 32 - _CountLeadingZeros(reverse);
+	return bit - 1;
+}
+
+#elif defined (__ARMCC_VERSION)
+/* RealView Compilation Tools for ARM */
+
+tlsf_decl int tlsf_ffs(unsigned int word)
+{
+	const unsigned int reverse = word & (~word + 1);
+	const int bit = 32 - __clz(reverse);
+	return bit - 1;
+}
+
+tlsf_decl int tlsf_fls(unsigned int word)
+{
+	const int bit = word ? 32 - __clz(word) : 0;
+	return bit - 1;
+}
+
+#elif defined (__ghs__)
+/* Green Hills support for PowerPC */
+
+#include <ppc_ghs.h>
+
+tlsf_decl int tlsf_ffs(unsigned int word)
+{
+	const unsigned int reverse = word & (~word + 1);
+	const int bit = 32 - __CLZ32(reverse);
+	return bit - 1;
+}
+
+tlsf_decl int tlsf_fls(unsigned int word)
+{
+	const int bit = word ? 32 - __CLZ32(word) : 0;
+	return bit - 1;
+}
+
+#else
+/* Fall back to generic implementation. */
+
+tlsf_decl int tlsf_fls_generic(unsigned int word)
+{
+	int bit = 32;
+
+	if (!word) bit -= 1;
+	if (!(word & 0xffff0000)) { word <<= 16; bit -= 16; }
+	if (!(word & 0xff000000)) { word <<= 8; bit -= 8; }
+	if (!(word & 0xf0000000)) { word <<= 4; bit -= 4; }
+	if (!(word & 0xc0000000)) { word <<= 2; bit -= 2; }
+	if (!(word & 0x80000000)) { word <<= 1; bit -= 1; }
+
+	return bit;
+}
+
+/* Implement ffs in terms of fls. */
+tlsf_decl int tlsf_ffs(unsigned int word)
+{
+	return tlsf_fls_generic(word & (~word + 1)) - 1;
+}
+
+tlsf_decl int tlsf_fls(unsigned int word)
+{
+	return tlsf_fls_generic(word) - 1;
+}
+
+#endif
+
+/* Possibly 64-bit version of tlsf_fls. */
+#if defined (TLSF_64BIT)
+tlsf_decl int tlsf_fls_sizet(size_t size)
+{
+	int high = (int)(size >> 32);
+	int bits = 0;
+	if (high)
+	{
+		bits = 32 + tlsf_fls(high);
+	}
+	else
+	{
+		bits = tlsf_fls((int)size & 0xffffffff);
+
+	}
+	return bits;
+}
+#else
+#define tlsf_fls_sizet tlsf_fls
+#endif
+
+#undef tlsf_decl
+
+#endif
-- 
1.7.7.3


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [RFC PATCH 2/3] adapt tlsf for barebox
  2011-12-08 14:03 [RFC PATCH 0/3] add tlsf memory allocator Antony Pavlov
  2011-12-08 14:03 ` [RFC PATCH 1/3] import TLSF 2.0 from http://tlsf.baisoku.org/tlsf-2.0.zip Antony Pavlov
@ 2011-12-08 14:03 ` Antony Pavlov
  2011-12-08 14:03 ` [RFC PATCH 3/3] add tlsf-based malloc implementation Antony Pavlov
  2011-12-09  9:17 ` [RFC PATCH 0/3] add tlsf memory allocator Sascha Hauer
  3 siblings, 0 replies; 10+ messages in thread
From: Antony Pavlov @ 2011-12-08 14:03 UTC (permalink / raw)
  To: barebox

Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
---
 common/tlsf.c  |   11 +++++++++++
 include/tlsf.h |    2 +-
 2 files changed, 12 insertions(+), 1 deletions(-)

diff --git a/common/tlsf.c b/common/tlsf.c
index 02dc8d4..b3de976 100644
--- a/common/tlsf.c
+++ b/common/tlsf.c
@@ -1,5 +1,7 @@
+#ifndef __BAREBOX__
 #include <assert.h>
 #include <limits.h>
+#endif
 #include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -8,6 +10,13 @@
 #include "tlsf.h"
 #include "tlsfbits.h"
 
+#ifdef __BAREBOX__
+#ifndef _DEBUG
+#define _DEBUG 0
+#endif
+#define tlsf_assert(expr)           ((void) (0))
+#endif
+
 /*
 ** Constants.
 */
@@ -82,6 +91,7 @@ enum tlsf_private
 #define tlsf_static_assert(exp) \
 	typedef char _tlsf_glue(static_assert, __LINE__) [(exp) ? 1 : -1]
 
+#ifndef __BAREBOX__
 /* This code has been tested on 32- and 64-bit (LP/LLP) architectures. */
 tlsf_static_assert(sizeof(int) * CHAR_BIT == 32);
 tlsf_static_assert(sizeof(size_t) * CHAR_BIT >= 32);
@@ -92,6 +102,7 @@ tlsf_static_assert(sizeof(unsigned int) * CHAR_BIT >= SL_INDEX_COUNT);
 
 /* Ensure we've properly tuned our sizes. */
 tlsf_static_assert(ALIGN_SIZE == SMALL_BLOCK_SIZE / SL_INDEX_COUNT);
+#endif
 
 /*
 ** Data structures and associated constants.
diff --git a/include/tlsf.h b/include/tlsf.h
index de7f90b..d575e16 100644
--- a/include/tlsf.h
+++ b/include/tlsf.h
@@ -43,7 +43,7 @@ int tlsf_check_heap(tlsf_pool pool);
 size_t tlsf_block_size(void* ptr);
 
 /* Overhead of per-pool internal structures. */
-size_t tlsf_overhead();
+size_t tlsf_overhead(void);
 
 #if defined(__cplusplus)
 };
-- 
1.7.7.3


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [RFC PATCH 3/3] add tlsf-based malloc implementation
  2011-12-08 14:03 [RFC PATCH 0/3] add tlsf memory allocator Antony Pavlov
  2011-12-08 14:03 ` [RFC PATCH 1/3] import TLSF 2.0 from http://tlsf.baisoku.org/tlsf-2.0.zip Antony Pavlov
  2011-12-08 14:03 ` [RFC PATCH 2/3] adapt tlsf for barebox Antony Pavlov
@ 2011-12-08 14:03 ` Antony Pavlov
  2011-12-09  9:31   ` Sascha Hauer
  2011-12-09  9:17 ` [RFC PATCH 0/3] add tlsf memory allocator Sascha Hauer
  3 siblings, 1 reply; 10+ messages in thread
From: Antony Pavlov @ 2011-12-08 14:03 UTC (permalink / raw)
  To: barebox

Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
---
 common/Kconfig       |    3 ++
 common/Makefile      |    2 +
 common/memory.c      |    8 +++++
 common/tlsf_malloc.c |   78 ++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 91 insertions(+), 0 deletions(-)
 create mode 100644 common/tlsf_malloc.c

diff --git a/common/Kconfig b/common/Kconfig
index 27464d1..71f092c 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -159,6 +159,9 @@ choice
 config MALLOC_DLMALLOC
 	bool "dlmalloc"
 
+config MALLOC_TLSF
+	bool "tlsf"
+
 config MALLOC_DUMMY
 	bool "dummy malloc"
 	depends on SHELL_NONE
diff --git a/common/Makefile b/common/Makefile
index 9bce479..467c666 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -14,6 +14,8 @@ obj-$(CONFIG_OFTREE)		+= oftree.o
 
 obj-y += memory.o
 obj-$(CONFIG_MALLOC_DLMALLOC) += dlmalloc.o
+obj-$(CONFIG_MALLOC_TLSF) += tlsf_malloc.o
+obj-$(CONFIG_MALLOC_TLSF) += tlsf.o
 obj-$(CONFIG_MALLOC_DUMMY) += dummy_malloc.o
 obj-y += clock.o
 obj-y += version.o
diff --git a/common/memory.c b/common/memory.c
index f0ae1cc..faff33b 100644
--- a/common/memory.c
+++ b/common/memory.c
@@ -47,11 +47,19 @@ unsigned long mem_malloc_end(void)
 	return malloc_end;
 }
 
+#ifdef CONFIG_MALLOC_TLSF
+#include <tlsf.h>
+tlsf_pool tlsf_mem_pool;
+#endif
+
 void mem_malloc_init(void *start, void *end)
 {
 	malloc_start = (unsigned long)start;
 	malloc_end = (unsigned long)end;
 	malloc_brk = malloc_start;
+#ifdef CONFIG_MALLOC_TLSF
+	tlsf_mem_pool = tlsf_create(start, (char *)end - (char *)start);
+#endif
 }
 
 #ifndef __SANDBOX__
diff --git a/common/tlsf_malloc.c b/common/tlsf_malloc.c
new file mode 100644
index 0000000..a6f82ba
--- /dev/null
+++ b/common/tlsf_malloc.c
@@ -0,0 +1,78 @@
+/*
+ * tlsf wrapper for barebox
+ *
+ * Copyright (C) 2011 Antony Pavlov <antonynpavlov@gmail.com>
+ *
+ * This file is part of barebox.
+ * See file CREDITS for list of people who contributed to this project.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <config.h>
+#include <malloc.h>
+#include <string.h>
+#include <malloc.h>
+
+#include <stdio.h>
+#include <module.h>
+#include <tlsf.h>
+
+extern tlsf_pool tlsf_mem_pool;
+
+void *malloc(size_t bytes)
+{
+	return tlsf_malloc(tlsf_mem_pool, bytes);
+}
+EXPORT_SYMBOL(malloc);
+
+/*
+ * calloc calls malloc, then zeroes out the allocated chunk.
+ */
+void *calloc(size_t n, size_t elem_size)
+{
+	void *mem;
+	size_t sz;
+
+	sz = n * elem_size;
+	mem = malloc(sz);
+	memset(mem, 0, sz);
+
+	return mem;
+}
+EXPORT_SYMBOL(calloc);
+
+void free(void *mem)
+{
+	tlsf_free(tlsf_mem_pool, mem);
+}
+EXPORT_SYMBOL(free);
+
+void *realloc(void *oldmem, size_t bytes)
+{
+	return tlsf_realloc(tlsf_mem_pool, oldmem, bytes);
+}
+EXPORT_SYMBOL(realloc);
+
+void *memalign(size_t alignment, size_t bytes)
+{
+	return tlsf_memalign(tlsf_mem_pool, alignment, bytes);
+}
+EXPORT_SYMBOL(memalign);
+
+#ifdef CONFIG_CMD_MEMINFO
+void malloc_stats(void)
+{
+}
+#endif /* CONFIG_CMD_MEMINFO */
-- 
1.7.7.3


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC PATCH 0/3] add tlsf memory allocator
  2011-12-08 14:03 [RFC PATCH 0/3] add tlsf memory allocator Antony Pavlov
                   ` (2 preceding siblings ...)
  2011-12-08 14:03 ` [RFC PATCH 3/3] add tlsf-based malloc implementation Antony Pavlov
@ 2011-12-09  9:17 ` Sascha Hauer
  2011-12-23 10:04   ` Sascha Hauer
  3 siblings, 1 reply; 10+ messages in thread
From: Sascha Hauer @ 2011-12-09  9:17 UTC (permalink / raw)
  To: Antony Pavlov; +Cc: barebox

Hi Antony,

On Thu, Dec 08, 2011 at 06:03:46PM +0400, Antony Pavlov wrote:
> This patch series adds the tlsf memory allocator to barebox.
> 
> TLSF: Two Level Segregated Fit memory allocator implementation.
> Written by Matthew Conte (matt@baisoku.org).
> Public Domain, no restrictions.
> 
> [RFC PATCH 1/3] import TLSF 2.0
> [RFC PATCH 2/3] adapt tlsf for barebox
> [RFC PATCH 3/3] add tlsf-based malloc implementation

The tlsf code looks really nice. Not that I even tried to understand it,
but it looks like one *could* understand the code when he has to (unlike
the dlmalloc code). It is also smaller in binary space and it has the
great advantage of having memory pools. Memory pools can be useful to
seperate the general malloc space from the ramfs malloc space, so that
a full ramfs does not crash barebox. It could also be used to implement
dma_alloc_coherent().

Unfortunately there are two downsides. As the author already says on the
webpage it's slightly slower than dlmalloc. That's ok as long we do not
store big files in ramfs. The second one is that it needs a
memset(pool, 0, size) on initialization. Without it I was not able to
test your patches as barebox crashes before even the console was
initialized. This memset can take quite a long time. Maybe we should ask
Matthew if we really have to clear the pool completely or if it's enough
to clear certain parts of it.

Overall I think we should give these patches a try as an alternative
malloc implementation with the perspective of replacing dlmalloc
completely some day.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC PATCH 1/3] import TLSF 2.0 from http://tlsf.baisoku.org/tlsf-2.0.zip
  2011-12-08 14:03 ` [RFC PATCH 1/3] import TLSF 2.0 from http://tlsf.baisoku.org/tlsf-2.0.zip Antony Pavlov
@ 2011-12-09  9:24   ` Sascha Hauer
  0 siblings, 0 replies; 10+ messages in thread
From: Sascha Hauer @ 2011-12-09  9:24 UTC (permalink / raw)
  To: Antony Pavlov; +Cc: barebox

On Thu, Dec 08, 2011 at 06:03:47PM +0400, Antony Pavlov wrote:
> TLSF: Two Level Segregated Fit memory allocator implementation.
> Written by Matthew Conte (matt@baisoku.org).
> Public Domain, no restrictions.
> 
> Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
> ---
>  common/tlsf.c      |  961 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  include/tlsf.h     |   52 +++
>  include/tlsfbits.h |  180 ++++++++++
>  3 files changed, 1193 insertions(+), 0 deletions(-)
>  create mode 100644 common/tlsf.c
>  create mode 100644 include/tlsf.h
>  create mode 100644 include/tlsfbits.h
> 
> diff --git a/common/tlsf.c b/common/tlsf.c
> new file mode 100644
> index 0000000..02dc8d4
> --- /dev/null
> +++ b/common/tlsf.c
> @@ -0,0 +1,961 @@

We should probably add a header here and at least say where the code
comes from. 'not subject to any licensing restrictions' for me means
that we can just add the standard GPL header here, but I'm no lawyer.


> diff --git a/include/tlsfbits.h b/include/tlsfbits.h
> new file mode 100644
> index 0000000..3e5c82a
> --- /dev/null
> +++ b/include/tlsfbits.h
> @@ -0,0 +1,180 @@
> +#ifndef INCLUDED_tlsfbits
> +#define INCLUDED_tlsfbits
> +
> +#if defined(__cplusplus)
> +#define tlsf_decl inline
> +#else
> +#define tlsf_decl static
> +#endif
> +
> +/*
> +** Architecture-specific bit manipulation routines.
> +**
> +** TLSF achieves O(1) cost for malloc and free operations by limiting
> +** the search for a free block to a free list of guaranteed size
> +** adequate to fulfill the request, combined with efficient free list
> +** queries using bitmasks and architecture-specific bit-manipulation
> +** routines.
> +**
> +** Most modern processors provide instructions to count leading zeroes
> +** in a word, find the lowest and highest set bit, etc. These
> +** specific implementations will be used when available, falling back
> +** to a reasonably efficient generic implementation.
> +**
> +** NOTE: TLSF spec relies on ffs/fls returning value 0..31.
> +** ffs/fls return 1-32 by default, returning 0 for error.
> +*/
> +
> +/*
> +** Detect whether or not we are building for a 32- or 64-bit (LP/LLP)
> +** architecture. There is no reliable portable method at compile-time.
> +*/
> +#if defined (__alpha__) || defined (__ia64__) || defined (__x86_64__) \
> +	|| defined (_WIN64) || defined (__LP64__) || defined (__LLP64__)
> +#define TLSF_64BIT
> +#endif

We should throw these ifdefs away and just use:

#include <linux/bitops.h>

tlsf_decl int tlsf_ffs(unsigned int word)
{
	return ffs(word) - 1;
}

tlsf_decl int tlsf_fls(unsigned int word)
{
	return fls(word) - 1;
}

You could fold this into the barebox adoption patch so that we still
have the original import clean.


Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC PATCH 3/3] add tlsf-based malloc implementation
  2011-12-08 14:03 ` [RFC PATCH 3/3] add tlsf-based malloc implementation Antony Pavlov
@ 2011-12-09  9:31   ` Sascha Hauer
  0 siblings, 0 replies; 10+ messages in thread
From: Sascha Hauer @ 2011-12-09  9:31 UTC (permalink / raw)
  To: Antony Pavlov; +Cc: barebox

On Thu, Dec 08, 2011 at 06:03:49PM +0400, Antony Pavlov wrote:
> Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
> ---
>  common/Kconfig       |    3 ++
>  common/Makefile      |    2 +
>  common/memory.c      |    8 +++++
>  common/tlsf_malloc.c |   78 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 91 insertions(+), 0 deletions(-)
>  create mode 100644 common/tlsf_malloc.c
> 
> diff --git a/common/Kconfig b/common/Kconfig
> index 27464d1..71f092c 100644
> --- a/common/Kconfig
> +++ b/common/Kconfig
> @@ -159,6 +159,9 @@ choice
>  config MALLOC_DLMALLOC
>  	bool "dlmalloc"
>  
> +config MALLOC_TLSF
> +	bool "tlsf"
> +
>  config MALLOC_DUMMY
>  	bool "dummy malloc"
>  	depends on SHELL_NONE
> diff --git a/common/Makefile b/common/Makefile
> index 9bce479..467c666 100644
> --- a/common/Makefile
> +++ b/common/Makefile
> @@ -14,6 +14,8 @@ obj-$(CONFIG_OFTREE)		+= oftree.o
>  
>  obj-y += memory.o
>  obj-$(CONFIG_MALLOC_DLMALLOC) += dlmalloc.o
> +obj-$(CONFIG_MALLOC_TLSF) += tlsf_malloc.o
> +obj-$(CONFIG_MALLOC_TLSF) += tlsf.o
>  obj-$(CONFIG_MALLOC_DUMMY) += dummy_malloc.o
>  obj-y += clock.o
>  obj-y += version.o
> diff --git a/common/memory.c b/common/memory.c
> index f0ae1cc..faff33b 100644
> --- a/common/memory.c
> +++ b/common/memory.c
> @@ -47,11 +47,19 @@ unsigned long mem_malloc_end(void)
>  	return malloc_end;
>  }
>  
> +#ifdef CONFIG_MALLOC_TLSF
> +#include <tlsf.h>
> +tlsf_pool tlsf_mem_pool;
> +#endif
> +
>  void mem_malloc_init(void *start, void *end)
>  {
>  	malloc_start = (unsigned long)start;
>  	malloc_end = (unsigned long)end;
>  	malloc_brk = malloc_start;
> +#ifdef CONFIG_MALLOC_TLSF
> +	tlsf_mem_pool = tlsf_create(start, (char *)end - (char *)start);
> +#endif
>  }
>  
>  #ifndef __SANDBOX__
> +
> +#ifdef CONFIG_CMD_MEMINFO
> +void malloc_stats(void)
> +{
> +}
> +#endif /* CONFIG_CMD_MEMINFO */

An implementation of malloc_stats would be nice. It's a good thing
during development to be able to find memory leaks. For now it's ok
as we can still use the dlmalloc implementation for this. Anyway,
you should add a 'depends on MALLOC_DLMALLOC' to the meminfo command
instead. Currently we have a meminfo command which just produces no
output.

Sascha


-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC PATCH 0/3] add tlsf memory allocator
  2011-12-09  9:17 ` [RFC PATCH 0/3] add tlsf memory allocator Sascha Hauer
@ 2011-12-23 10:04   ` Sascha Hauer
  2011-12-23 11:20     ` Antony Pavlov
  0 siblings, 1 reply; 10+ messages in thread
From: Sascha Hauer @ 2011-12-23 10:04 UTC (permalink / raw)
  To: Antony Pavlov; +Cc: barebox

On Fri, Dec 09, 2011 at 10:17:29AM +0100, Sascha Hauer wrote:
> Hi Antony,
> 
> On Thu, Dec 08, 2011 at 06:03:46PM +0400, Antony Pavlov wrote:
> > This patch series adds the tlsf memory allocator to barebox.
> > 
> > TLSF: Two Level Segregated Fit memory allocator implementation.
> > Written by Matthew Conte (matt@baisoku.org).
> > Public Domain, no restrictions.
> > 
> > [RFC PATCH 1/3] import TLSF 2.0
> > [RFC PATCH 2/3] adapt tlsf for barebox
> > [RFC PATCH 3/3] add tlsf-based malloc implementation
> 
> The tlsf code looks really nice. Not that I even tried to understand it,
> but it looks like one *could* understand the code when he has to (unlike
> the dlmalloc code). It is also smaller in binary space and it has the
> great advantage of having memory pools. Memory pools can be useful to
> seperate the general malloc space from the ramfs malloc space, so that
> a full ramfs does not crash barebox. It could also be used to implement
> dma_alloc_coherent().
> 
> Unfortunately there are two downsides. As the author already says on the
> webpage it's slightly slower than dlmalloc. That's ok as long we do not
> store big files in ramfs. The second one is that it needs a
> memset(pool, 0, size) on initialization. Without it I was not able to
> test your patches as barebox crashes before even the console was
> initialized.

This issue goes down to a bug in the console drivers. The most console
drivers use xmalloc instead of xzalloc which caused unitialized flags.
Somehow the tlsf allocater triggered this.

So I'm going to merge this series.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC PATCH 0/3] add tlsf memory allocator
  2011-12-23 10:04   ` Sascha Hauer
@ 2011-12-23 11:20     ` Antony Pavlov
  0 siblings, 0 replies; 10+ messages in thread
From: Antony Pavlov @ 2011-12-23 11:20 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: barebox

On 23 December 2011 14:04, Sascha Hauer <s.hauer@pengutronix.de> wrote:
> On Fri, Dec 09, 2011 at 10:17:29AM +0100, Sascha Hauer wrote:
>> Hi Antony,
>>
>> On Thu, Dec 08, 2011 at 06:03:46PM +0400, Antony Pavlov wrote:
>> > This patch series adds the tlsf memory allocator to barebox.
>> >
>> > TLSF: Two Level Segregated Fit memory allocator implementation.
>> > Written by Matthew Conte (matt@baisoku.org).
>> > Public Domain, no restrictions.
>> >
>> > [RFC PATCH 1/3] import TLSF 2.0
>> > [RFC PATCH 2/3] adapt tlsf for barebox
>> > [RFC PATCH 3/3] add tlsf-based malloc implementation
>>
>> The tlsf code looks really nice. Not that I even tried to understand it,
>> but it looks like one *could* understand the code when he has to (unlike
>> the dlmalloc code). It is also smaller in binary space and it has the
>> great advantage of having memory pools. Memory pools can be useful to
>> seperate the general malloc space from the ramfs malloc space, so that
>> a full ramfs does not crash barebox. It could also be used to implement
>> dma_alloc_coherent().
>>
>> Unfortunately there are two downsides. As the author already says on the
>> webpage it's slightly slower than dlmalloc. That's ok as long we do not
>> store big files in ramfs. The second one is that it needs a
>> memset(pool, 0, size) on initialization. Without it I was not able to
>> test your patches as barebox crashes before even the console was
>> initialized.
>
> This issue goes down to a bug in the console drivers. The most console
> drivers use xmalloc instead of xzalloc which caused unitialized flags.
> Somehow the tlsf allocater triggered this.
>
> So I'm going to merge this series.

Thank you, Sascha!

-- 
Best regards,
  Antony Pavlov

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [RFC PATCH 3/3] add tlsf-based malloc implementation
  2011-09-14 22:03 [RFC PATCH 1/3] " Antony Pavlov
@ 2011-09-14 22:03 ` Antony Pavlov
  0 siblings, 0 replies; 10+ messages in thread
From: Antony Pavlov @ 2011-09-14 22:03 UTC (permalink / raw)
  To: barebox

Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
---
 common/Kconfig       |    3 ++
 common/Makefile      |    2 +
 common/memory.c      |    7 +++++
 common/tlsf_malloc.c |   71 ++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 83 insertions(+), 0 deletions(-)
 create mode 100644 common/tlsf_malloc.c

diff --git a/common/Kconfig b/common/Kconfig
index 422d185..83cb842 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -150,6 +150,9 @@ choice
 config MALLOC_DLMALLOC
 	bool "dlmalloc"
 
+config MALLOC_TLSF
+	bool "tlsf"
+
 config MALLOC_DUMMY
 	bool "dummy malloc"
 	depends on SHELL_NONE
diff --git a/common/Makefile b/common/Makefile
index 74946e9..2e33176 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -11,6 +11,8 @@ obj-$(CONFIG_CMD_LOADS)		+= s_record.o
 
 obj-y += memory.o
 obj-$(CONFIG_MALLOC_DLMALLOC) += dlmalloc.o
+obj-$(CONFIG_MALLOC_TLSF) += tlsf_malloc.o
+obj-$(CONFIG_MALLOC_TLSF) += tlsf.o
 obj-$(CONFIG_MALLOC_DUMMY) += dummy_malloc.o
 obj-y += clock.o
 obj-y += version.o
diff --git a/common/memory.c b/common/memory.c
index 8f4a768..56c80bc 100644
--- a/common/memory.c
+++ b/common/memory.c
@@ -39,11 +39,18 @@ unsigned long mem_malloc_end(void)
 	return malloc_end;
 }
 
+#ifdef CONFIG_MALLOC_TLSF
+#include <tlsf.h>
+#endif
+
 void mem_malloc_init(void *start, void *end)
 {
 	malloc_start = (unsigned long)start;
 	malloc_end = (unsigned long)end;
 	malloc_brk = malloc_start;
+#ifdef CONFIG_MALLOC_TLSF
+	init_memory_pool((char *)end - (char *)start, start);
+#endif
 }
 
 static void *sbrk_no_zero(ptrdiff_t increment)
diff --git a/common/tlsf_malloc.c b/common/tlsf_malloc.c
new file mode 100644
index 0000000..2380d18
--- /dev/null
+++ b/common/tlsf_malloc.c
@@ -0,0 +1,71 @@
+/*
+ * tlsf wrapper for barebox
+ *
+ * Copyright (C) 2011 Antony Pavlov <antonynpavlov@gmail.com>
+ *
+ * This file is part of barebox.
+ * See file CREDITS for list of people who contributed to this project.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <config.h>
+#include <malloc.h>
+#include <string.h>
+#include <mem_malloc.h>
+
+#include <stdio.h>
+#include <module.h>
+#include <tlsf.h>
+
+void *malloc(size_t bytes)
+{
+	return tlsf_malloc(bytes);
+}
+EXPORT_SYMBOL(malloc);
+
+/*
+ * calloc calls malloc, then zeroes out the allocated chunk.
+ */
+void *calloc(size_t n, size_t elem_size)
+{
+	return tlsf_calloc(n, elem_size);
+}
+EXPORT_SYMBOL(calloc);
+
+void free(void *mem)
+{
+	tlsf_free(mem);
+}
+EXPORT_SYMBOL(free);
+
+void *realloc(void *oldmem, size_t bytes)
+{
+	return tlsf_realloc(oldmem, bytes);
+
+}
+EXPORT_SYMBOL(realloc);
+
+/* FIXME */
+void *memalign(size_t alignment, size_t bytes)
+{
+	return malloc(bytes);
+}
+EXPORT_SYMBOL(memalign);
+
+#ifdef CONFIG_CMD_MEMINFO
+void malloc_stats(void)
+{
+}
+#endif /* CONFIG_CMD_MEMINFO */
-- 
1.7.5.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2011-12-23 11:20 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-12-08 14:03 [RFC PATCH 0/3] add tlsf memory allocator Antony Pavlov
2011-12-08 14:03 ` [RFC PATCH 1/3] import TLSF 2.0 from http://tlsf.baisoku.org/tlsf-2.0.zip Antony Pavlov
2011-12-09  9:24   ` Sascha Hauer
2011-12-08 14:03 ` [RFC PATCH 2/3] adapt tlsf for barebox Antony Pavlov
2011-12-08 14:03 ` [RFC PATCH 3/3] add tlsf-based malloc implementation Antony Pavlov
2011-12-09  9:31   ` Sascha Hauer
2011-12-09  9:17 ` [RFC PATCH 0/3] add tlsf memory allocator Sascha Hauer
2011-12-23 10:04   ` Sascha Hauer
2011-12-23 11:20     ` Antony Pavlov
  -- strict thread matches above, loose matches on Subject: below --
2011-09-14 22:03 [RFC PATCH 1/3] " Antony Pavlov
2011-09-14 22:03 ` [RFC PATCH 3/3] add tlsf-based malloc implementation Antony Pavlov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox