From fee29436b0ecc55390a3c9f356104654b8bfe042 Mon Sep 17 00:00:00 2001 From: Georg Reinke Date: Mon, 27 Mar 2017 13:22:54 +0200 Subject: [PATCH 01/15] implement managed memtype --- include/villas/memory.h | 40 +++++++++++--- include/villas/pool.h | 6 +-- include/villas/queue.h | 6 +-- lib/memory.c | 115 +++++++++++++++++++++++++++++++++++----- lib/pool.c | 4 +- lib/queue.c | 2 +- 6 files changed, 144 insertions(+), 29 deletions(-) diff --git a/include/villas/memory.h b/include/villas/memory.h index 9a3084544..bcf96a5a1 100644 --- a/include/villas/memory.h +++ b/include/villas/memory.h @@ -13,8 +13,10 @@ #define HUGEPAGESIZE (1 << 21) -typedef void *(*memzone_allocator_t)(size_t len, size_t alignment); -typedef int (*memzone_deallocator_t)(void *ptr, size_t len); +struct memtype; + +typedef void *(*memzone_allocator_t)(struct memtype *mem, size_t len, size_t alignment); +typedef int (*memzone_deallocator_t)(struct memtype *mem, void *ptr, size_t len); enum memtype_flags { MEMORY_MMAP = (1 << 0), @@ -33,6 +35,26 @@ struct memtype { memzone_deallocator_t free; }; +enum memblock_flags { + MEMBLOCK_USED = 1, +}; + +// Descriptor of a memory block. Associated block always starts at +// &m + sizeof(struct memblock). +struct memblock { + struct memblock* prev; + struct memblock* next; + size_t len; + int flags; +}; + +struct memtype_managed { + struct memtype mt; + void *base; + size_t len; + struct memblock *first; +}; + /** @todo Unused for now */ struct memzone { struct memtype * const type; @@ -50,13 +72,15 @@ int memory_init(); * @retval NULL If allocation failed. * @retval <>0 If allocation was successful. */ -void * memory_alloc(const struct memtype *m, size_t len); +void * memory_alloc(struct memtype *m, size_t len); -void * memory_alloc_aligned(const struct memtype *m, size_t len, size_t alignment); +void * memory_alloc_aligned(struct memtype *m, size_t len, size_t alignment); -int memory_free(const struct memtype *m, void *ptr, size_t len); +int memory_free(struct memtype *m, void *ptr, size_t len); -extern const struct memtype memtype_heap; -extern const struct memtype memtype_hugepage; +struct memtype* memtype_managed_init(void *ptr, size_t len); -#endif /* _MEMORY_H_ */ \ No newline at end of file +extern struct memtype memtype_heap; +extern struct memtype memtype_hugepage; + +#endif /* _MEMORY_H_ */ diff --git a/include/villas/pool.h b/include/villas/pool.h index 38b017a7f..13f0e5d7b 100644 --- a/include/villas/pool.h +++ b/include/villas/pool.h @@ -18,7 +18,7 @@ /** A thread-safe memory pool */ struct pool { void *buffer; /**< Address of the underlying memory area */ - const struct memtype *mem; + struct memtype *mem; size_t len; /**< Length of the underlying memory area */ @@ -31,7 +31,7 @@ struct pool { #define INLINE static inline __attribute__((unused)) /** Initiazlize a pool */ -int pool_init(struct pool *p, size_t cnt, size_t blocksz, const struct memtype *mem); +int pool_init(struct pool *p, size_t cnt, size_t blocksz, struct memtype *mem); /** Destroy and release memory used by pool. */ int pool_destroy(struct pool *p); @@ -61,4 +61,4 @@ INLINE int pool_put(struct pool *p, void *buf) return queue_push(&p->queue, buf); } -#endif /* _POOL_H_ */ \ No newline at end of file +#endif /* _POOL_H_ */ diff --git a/include/villas/queue.h b/include/villas/queue.h index 50fa5aff9..17a76724b 100644 --- a/include/villas/queue.h +++ b/include/villas/queue.h @@ -45,7 +45,7 @@ typedef char cacheline_pad_t[CACHELINE_SIZE]; struct queue { cacheline_pad_t _pad0; /**< Shared area: all threads read */ - struct memtype const * mem; + struct memtype * mem; size_t buffer_mask; struct queue_cell { atomic_size_t sequence; @@ -64,7 +64,7 @@ struct queue { }; /** Initialize MPMC queue */ -int queue_init(struct queue *q, size_t size, const struct memtype *mem); +int queue_init(struct queue *q, size_t size, struct memtype *mem); /** Desroy MPMC queue and release memory */ int queue_destroy(struct queue *q); @@ -84,4 +84,4 @@ int queue_push_many(struct queue *q, void *ptr[], size_t cnt); int queue_pull_many(struct queue *q, void *ptr[], size_t cnt); -#endif /* _MPMC_QUEUE_H_ */ \ No newline at end of file +#endif /* _MPMC_QUEUE_H_ */ diff --git a/lib/memory.c b/lib/memory.c index f8f2ebe8a..a8b9d708a 100644 --- a/lib/memory.c +++ b/lib/memory.c @@ -30,31 +30,31 @@ int memory_init() return 0; } -void * memory_alloc(const struct memtype *m, size_t len) +void * memory_alloc(struct memtype *m, size_t len) { - void *ptr = m->alloc(len, sizeof(void *)); + void *ptr = m->alloc(m, len, sizeof(void *)); debug(DBG_MEM | 2, "Allocated %#zx bytes of %s memory: %p", len, m->name, ptr); return ptr; } -void * memory_alloc_aligned(const struct memtype *m, size_t len, size_t alignment) +void * memory_alloc_aligned(struct memtype *m, size_t len, size_t alignment) { - void *ptr = m->alloc(len, alignment); + void *ptr = m->alloc(m, len, alignment); debug(DBG_MEM | 2, "Allocated %#zx bytes of %#zx-byte-aligned %s memory: %p", len, alignment, m->name, ptr); return ptr; } -int memory_free(const struct memtype *m, void *ptr, size_t len) +int memory_free(struct memtype *m, void *ptr, size_t len) { debug(DBG_MEM | 2, "Releasing %#zx bytes of %s memory", len, m->name); - return m->free(ptr, len); + return m->free(m, ptr, len); } -static void * memory_heap_alloc(size_t len, size_t alignment) +static void * memory_heap_alloc(struct memtype *m, size_t len, size_t alignment) { void *ptr; int ret; @@ -67,7 +67,7 @@ static void * memory_heap_alloc(size_t len, size_t alignment) return ret ? NULL : ptr; } -int memory_heap_free(void *ptr, size_t len) +int memory_heap_free(struct memtype *m, void *ptr, size_t len) { free(ptr); @@ -75,7 +75,7 @@ int memory_heap_free(void *ptr, size_t len) } /** Allocate memory backed by hugepages with malloc() like interface */ -static void * memory_hugepage_alloc(size_t len, size_t alignment) +static void * memory_hugepage_alloc(struct memtype *m, size_t len, size_t alignment) { int prot = PROT_READ | PROT_WRITE; int flags = MAP_PRIVATE | MAP_ANONYMOUS; @@ -96,15 +96,106 @@ static void * memory_hugepage_alloc(size_t len, size_t alignment) return ret; } -static int memory_hugepage_free(void *ptr, size_t len) +static int memory_hugepage_free(struct memtype *m, void *ptr, size_t len) { len = ALIGN(len, HUGEPAGESIZE); /* ugly see: https://lkml.org/lkml/2015/3/27/171 */ return munmap(ptr, len); } +void* memory_managed_alloc(struct memtype *m, size_t len, size_t alignment) { + // Simple first-fit allocation. + struct memtype_managed* man = (struct memtype_managed*) m; + struct memblock* block; + for (block = man->first; block != NULL; block = block->next) { + if (block->flags & MEMBLOCK_USED) + continue; + char* cptr = (char*) block + sizeof(struct memblock); + size_t avail = block->len; + uintptr_t uptr = (uintptr_t) cptr; + // check alignment first + uintptr_t rem = uptr % alignment; + if (rem != 0) { + cptr += alignment - rem; + avail -= alignment - rem; + } + // TODO: if alignment is large, we may waste a lot of memory here. + if (avail > len + sizeof(struct memblock)) { + struct memblock *newblock = (struct memblock*) (cptr + len); + newblock->prev = block; + newblock->next = block->next; + block->next = newblock; + if (newblock->next) + newblock->next->prev = newblock; + newblock->flags = 0; + newblock->len = (char*) block + block->len - cptr - sizeof(struct memblock); + block->flags |= MEMBLOCK_USED; + return (void*) cptr; + } + } + // no suitable block found + return NULL; +} + +int memory_managed_free(struct memtype *m, void *ptr, size_t len) { + struct memtype_managed* man = (struct memtype_managed*) m; + char* cptr = (char*) ptr; + struct memblock* block; + for (block = man->first; block != NULL; block = block->next) { + if (!(block->flags & MEMBLOCK_USED)) + continue; + // since we may waste some memory at the start of a block to ensure + // alignment, ptr may not actually be the start of the block + if ((char*) block + sizeof(struct memblock) <= cptr && + cptr < (char*) block + block->len) { + // try to merge it with a neighbouring free block + if (block->prev && !(block->prev->flags & MEMBLOCK_USED)) { + block->prev->len += block->len + sizeof(struct memblock); + block->prev->next = block->next; + if (block->next) + block->next->prev = block->prev; + } else if (block->next && !(block->next->flags & MEMBLOCK_USED)) { + block->len += block->next->len + sizeof(struct memblock); + block->next = block->next->next; + if (block->next) + block->next->prev = block; + } else { + block->flags &= (~MEMBLOCK_USED); + } + return 0; + } + } + return -1; +} + +struct memtype* memtype_managed_init(void *ptr, size_t len) { + if (len < sizeof(struct memtype_managed) + sizeof(struct memblock)) { + info("memtype_managed: passed region too small"); + return NULL; + } + struct memtype_managed *man = (struct memtype_managed*) ptr; + man->mt.name = "managed"; + man->mt.flags = 0; // TODO + man->mt.alloc = memory_managed_alloc; + man->mt.free = memory_managed_free; + man->mt.alignment = 1; + man->base = ptr; + man->len = len; + + char *cptr = (char*) ptr; + cptr += ALIGN(sizeof(struct memtype_managed), sizeof(void*)); + man->first = (struct memblock*) ((void*) cptr); + man->first->prev = NULL; + man->first->next = NULL; + cptr += ALIGN(sizeof(struct memblock), sizeof(void*)); + man->first->len = len - (cptr - (char*) ptr); + man->first->flags = 0; + + return (struct memtype*) man; +} + /* List of available memory types */ -const struct memtype memtype_heap = { +struct memtype memtype_heap = { .name = "heap", .flags = MEMORY_HEAP, .alloc = memory_heap_alloc, @@ -112,7 +203,7 @@ const struct memtype memtype_heap = { .alignment = 1 }; -const struct memtype memtype_hugepage = { +struct memtype memtype_hugepage = { .name = "mmap_hugepages", .flags = MEMORY_MMAP | MEMORY_HUGEPAGE, .alloc = memory_hugepage_alloc, diff --git a/lib/pool.c b/lib/pool.c index e2dc3f9c9..b9fe4482b 100644 --- a/lib/pool.c +++ b/lib/pool.c @@ -10,7 +10,7 @@ #include "memory.h" #include "kernel/kernel.h" -int pool_init(struct pool *p, size_t cnt, size_t blocksz, const struct memtype *m) +int pool_init(struct pool *p, size_t cnt, size_t blocksz, struct memtype *m) { int ret; @@ -39,4 +39,4 @@ int pool_destroy(struct pool *p) queue_destroy(&p->queue); return memory_free(p->mem, p->buffer, p->len); -} \ No newline at end of file +} diff --git a/lib/queue.c b/lib/queue.c index 20a7a6710..fdd1c09f3 100644 --- a/lib/queue.c +++ b/lib/queue.c @@ -35,7 +35,7 @@ #include "utils.h" /** Initialize MPMC queue */ -int queue_init(struct queue *q, size_t size, const struct memtype *mem) +int queue_init(struct queue *q, size_t size, struct memtype *mem) { /* Queue size must be 2 exponent */ From af7c64e53162284c6e19a720985cfe8506996f08 Mon Sep 17 00:00:00 2001 From: Georg Reinke Date: Tue, 28 Mar 2017 10:28:20 +0200 Subject: [PATCH 02/15] fix tests not compiling --- tests/memory.c | 6 +++--- tests/pool.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/memory.c b/tests/memory.c index 56bce7f7e..8e8637051 100644 --- a/tests/memory.c +++ b/tests/memory.c @@ -15,10 +15,10 @@ TheoryDataPoints(memory, aligned) = { DataPoints(size_t, 1, 32, 55, 1 << 10, 1 << 20), DataPoints(size_t, 1, 8, 1 << 12), - DataPoints(const struct memtype *, &memtype_heap, &memtype_hugepage) + DataPoints(struct memtype *, &memtype_heap, &memtype_hugepage) }; -Theory((size_t len, size_t align, const struct memtype *m), memory, aligned) { +Theory((size_t len, size_t align, struct memtype *m), memory, aligned) { int ret; void *ptr; @@ -33,4 +33,4 @@ Theory((size_t len, size_t align, const struct memtype *m), memory, aligned) { ret = memory_free(m, ptr, len); cr_assert_eq(ret, 0, "Failed to release memory: ret=%d, ptr=%p, len=%zu: %s", ret, ptr, len, strerror(errno)); -} \ No newline at end of file +} diff --git a/tests/pool.c b/tests/pool.c index e871e6041..19191c993 100644 --- a/tests/pool.c +++ b/tests/pool.c @@ -16,7 +16,7 @@ struct param { int thread_count; int pool_size; size_t block_size; - const struct memtype *memtype; + struct memtype *memtype; }; ParameterizedTestParameters(pool, basic) @@ -63,4 +63,4 @@ ParameterizedTest(struct param *p, pool, basic) ret = pool_destroy(&pool); cr_assert_eq(ret, 0, "Failed to destroy pool"); -} \ No newline at end of file +} From 25c7952cff5dd76ca5e13739fb6286c6af2379a9 Mon Sep 17 00:00:00 2001 From: Georg Reinke Date: Tue, 28 Mar 2017 11:30:57 +0200 Subject: [PATCH 03/15] memtype-managed: fix some alignment / edge cases --- include/villas/memory.h | 2 +- lib/memory.c | 66 ++++++++++++++++++++++++++++++----------- 2 files changed, 50 insertions(+), 18 deletions(-) diff --git a/include/villas/memory.h b/include/villas/memory.h index bcf96a5a1..e1ee37267 100644 --- a/include/villas/memory.h +++ b/include/villas/memory.h @@ -44,7 +44,7 @@ enum memblock_flags { struct memblock { struct memblock* prev; struct memblock* next; - size_t len; + size_t len; // lenght of the block; doesn't include the descriptor itself int flags; }; diff --git a/lib/memory.c b/lib/memory.c index a8b9d708a..1e7f10e65 100644 --- a/lib/memory.c +++ b/lib/memory.c @@ -103,7 +103,8 @@ static int memory_hugepage_free(struct memtype *m, void *ptr, size_t len) return munmap(ptr, len); } -void* memory_managed_alloc(struct memtype *m, size_t len, size_t alignment) { +void* memory_managed_alloc(struct memtype *m, size_t len, size_t alignment) +{ // Simple first-fit allocation. struct memtype_managed* man = (struct memtype_managed*) m; struct memblock* block; @@ -113,22 +114,50 @@ void* memory_managed_alloc(struct memtype *m, size_t len, size_t alignment) { char* cptr = (char*) block + sizeof(struct memblock); size_t avail = block->len; uintptr_t uptr = (uintptr_t) cptr; - // check alignment first + // check alignment first; leave a gap at start of block to assure + // alignment if necessary uintptr_t rem = uptr % alignment; + uintptr_t gap = 0; if (rem != 0) { - cptr += alignment - rem; - avail -= alignment - rem; + gap = alignment - rem; + cptr += gap; + avail -= gap; } - // TODO: if alignment is large, we may waste a lot of memory here. - if (avail > len + sizeof(struct memblock)) { - struct memblock *newblock = (struct memblock*) (cptr + len); - newblock->prev = block; - newblock->next = block->next; - block->next = newblock; - if (newblock->next) - newblock->next->prev = newblock; - newblock->flags = 0; - newblock->len = (char*) block + block->len - cptr - sizeof(struct memblock); + if (avail >= len) { + if (gap > sizeof(struct memblock)) { + // the alignment gap is big enough to fit another block. + // the original block descriptor is already at the correct + // position, so we just change its len and create a new block + // descriptor for the actual block we're handling. + block->len = gap; + struct memblock *newblock = (struct memblock*) (cptr - sizeof(struct memblock)); + newblock->prev = block; + newblock->next = block->next; + block->next = newblock; + newblock->flags = 0; + newblock->len = len; + block = newblock; + } else { + // the gap is too small to fit another block descriptor, so we + // must account for the gap length in the block length. + block->len = len + gap; + } + if (avail > len + sizeof(struct memblock)) { + // imperfect fit, so create another block for the remaining part + struct memblock *newblock = (struct memblock*) (cptr + len); + newblock->prev = block; + newblock->next = block->next; + block->next = newblock; + if (newblock->next) + newblock->next->prev = newblock; + newblock->flags = 0; + newblock->len = avail - len - sizeof(struct memblock); + } else { + // if this block was larger than the requested length, but only + // by less than sizeof(struct memblock), we may have wasted + // memory by previous assignments to block->len + block->len = avail; + } block->flags |= MEMBLOCK_USED; return (void*) cptr; } @@ -137,7 +166,8 @@ void* memory_managed_alloc(struct memtype *m, size_t len, size_t alignment) { return NULL; } -int memory_managed_free(struct memtype *m, void *ptr, size_t len) { +int memory_managed_free(struct memtype *m, void *ptr, size_t len) +{ struct memtype_managed* man = (struct memtype_managed*) m; char* cptr = (char*) ptr; struct memblock* block; @@ -147,7 +177,7 @@ int memory_managed_free(struct memtype *m, void *ptr, size_t len) { // since we may waste some memory at the start of a block to ensure // alignment, ptr may not actually be the start of the block if ((char*) block + sizeof(struct memblock) <= cptr && - cptr < (char*) block + block->len) { + cptr < (char*) block + sizeof(struct memblock) + block->len) { // try to merge it with a neighbouring free block if (block->prev && !(block->prev->flags & MEMBLOCK_USED)) { block->prev->len += block->len + sizeof(struct memblock); @@ -160,6 +190,7 @@ int memory_managed_free(struct memtype *m, void *ptr, size_t len) { if (block->next) block->next->prev = block; } else { + // no neighbouring free block, so just mark it as free block->flags &= (~MEMBLOCK_USED); } return 0; @@ -168,7 +199,8 @@ int memory_managed_free(struct memtype *m, void *ptr, size_t len) { return -1; } -struct memtype* memtype_managed_init(void *ptr, size_t len) { +struct memtype* memtype_managed_init(void *ptr, size_t len) +{ if (len < sizeof(struct memtype_managed) + sizeof(struct memblock)) { info("memtype_managed: passed region too small"); return NULL; From dd738a64624799d47cdb3d465930675c9b7145ab Mon Sep 17 00:00:00 2001 From: Georg Reinke Date: Tue, 28 Mar 2017 12:06:10 +0200 Subject: [PATCH 04/15] add simple tests for memory allocator --- tests/memory.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/memory.c b/tests/memory.c index 8e8637051..e266ca8c2 100644 --- a/tests/memory.c +++ b/tests/memory.c @@ -34,3 +34,33 @@ Theory((size_t len, size_t align, struct memtype *m), memory, aligned) { ret = memory_free(m, ptr, len); cr_assert_eq(ret, 0, "Failed to release memory: ret=%d, ptr=%p, len=%zu: %s", ret, ptr, len, strerror(errno)); } + +Test(memory, manager) { + void *p = memory_alloc(&memtype_heap, 1<<10); + struct memtype *manager = memtype_managed_init(p, 1<<10); + + void *p1, *p2, *p3; + p1 = memory_alloc(manager, 16); + cr_assert(p1); + + p2 = memory_alloc(manager, 32); + cr_assert(p2); + + cr_assert(memory_free(manager, p1, 16) == 0); + + p1 = memory_alloc_aligned(manager, 128, 128); + cr_assert(p1); + cr_assert(IS_ALIGNED(p1, 128)); + + p3 = memory_alloc_aligned(manager, 128, 256); + cr_assert(p3); + cr_assert(IS_ALIGNED(p1, 256)); + + cr_assert(memory_free(manager, p2, 32) == 0); + cr_assert(memory_free(manager, p1, 128) == 0); + cr_assert(memory_free(manager, p3, 128) == 0); + + p1 = memory_alloc(manager, (1<<10)-sizeof(struct memblock)); + cr_assert(p1); + cr_assert(memory_free(manager, p1, (1<<10)-sizeof(struct memblock)) == 0); +} From 1fd368d36024b2bbacde376b258b0d33648ff538 Mon Sep 17 00:00:00 2001 From: Georg Reinke Date: Tue, 28 Mar 2017 12:52:21 +0200 Subject: [PATCH 05/15] fix possible underflow in memory manager --- lib/memory.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/memory.c b/lib/memory.c index 1e7f10e65..1cde4c9ae 100644 --- a/lib/memory.c +++ b/lib/memory.c @@ -120,6 +120,9 @@ void* memory_managed_alloc(struct memtype *m, size_t len, size_t alignment) uintptr_t gap = 0; if (rem != 0) { gap = alignment - rem; + if (gap > avail) + // next aligned address isn't in this block anymore + continue; cptr += gap; avail -= gap; } From 1b33861528041c0ba3f9b41f204e711424c4dce1 Mon Sep 17 00:00:00 2001 From: Georg Reinke Date: Tue, 28 Mar 2017 13:09:57 +0200 Subject: [PATCH 06/15] memtype-managed: correctly merge free blocks --- lib/memory.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/memory.c b/lib/memory.c index 1cde4c9ae..5e1ba2e99 100644 --- a/lib/memory.c +++ b/lib/memory.c @@ -181,8 +181,15 @@ int memory_managed_free(struct memtype *m, void *ptr, size_t len) // alignment, ptr may not actually be the start of the block if ((char*) block + sizeof(struct memblock) <= cptr && cptr < (char*) block + sizeof(struct memblock) + block->len) { - // try to merge it with a neighbouring free block - if (block->prev && !(block->prev->flags & MEMBLOCK_USED)) { + // try to merge it with neighbouring free blocks + if (block->prev && !(block->prev->flags & MEMBLOCK_USED) && + block->next && !(block->next->flags & MEMBLOCK_USED)) { + // special case first: both previous and next block are unused + block->prev->len += block->len + block->next->len + 2 * sizeof(struct memblock); + block->prev->next = block->next->next; + if (block->next->next) + block->next->next->prev = block->prev; + } else if (block->prev && !(block->prev->flags & MEMBLOCK_USED)) { block->prev->len += block->len + sizeof(struct memblock); block->prev->next = block->next; if (block->next) From ccdb41d9d24d1dfaadfc582defc55bfb660d148e Mon Sep 17 00:00:00 2001 From: Georg Reinke Date: Tue, 28 Mar 2017 13:10:33 +0200 Subject: [PATCH 07/15] memtype-managed: fixed wrong test assumption --- tests/memory.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/memory.c b/tests/memory.c index e266ca8c2..c7a9e7931 100644 --- a/tests/memory.c +++ b/tests/memory.c @@ -36,8 +36,10 @@ Theory((size_t len, size_t align, struct memtype *m), memory, aligned) { } Test(memory, manager) { - void *p = memory_alloc(&memtype_heap, 1<<10); - struct memtype *manager = memtype_managed_init(p, 1<<10); + size_t total_size = 1 << 10; + size_t max_block = total_size - sizeof(struct memtype_managed) - sizeof(struct memblock); + void *p = memory_alloc(&memtype_heap, total_size); + struct memtype *manager = memtype_managed_init(p, total_size); void *p1, *p2, *p3; p1 = memory_alloc(manager, 16); @@ -60,7 +62,8 @@ Test(memory, manager) { cr_assert(memory_free(manager, p1, 128) == 0); cr_assert(memory_free(manager, p3, 128) == 0); - p1 = memory_alloc(manager, (1<<10)-sizeof(struct memblock)); + + p1 = memory_alloc(manager, max_block); cr_assert(p1); - cr_assert(memory_free(manager, p1, (1<<10)-sizeof(struct memblock)) == 0); + cr_assert(memory_free(manager, p1, max_block) == 0); } From de1a9b4ab3b6003472adbee47173510a05075ce0 Mon Sep 17 00:00:00 2001 From: Georg Reinke Date: Tue, 28 Mar 2017 13:26:15 +0200 Subject: [PATCH 08/15] fix IS_ALIGNED macro The old macro lead to failures on the tester, even though the alignment actually was correct. --- include/villas/utils.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/villas/utils.h b/include/villas/utils.h index 9df8b9ba9..03e6ae686 100644 --- a/include/villas/utils.h +++ b/include/villas/utils.h @@ -51,7 +51,7 @@ #define ALIGN(x, a) ALIGN_MASK(x, (uintptr_t) (a) - 1) #define ALIGN_MASK(x, m) (((uintptr_t) (x) + (m)) & ~(m)) -#define IS_ALIGNED(x, a) (ALIGN(x, a) == (uintptr_t) x) +#define IS_ALIGNED(x, a) ((uintptr_t) (x) % (uintptr_t) (a) == 0) /** Round-up integer division */ #define CEIL(x, y) (((x) + (y) - 1) / (y)) @@ -228,4 +228,4 @@ static inline int log2i(long long x) { /** Sleep with rdtsc */ void rdtsc_sleep(uint64_t nanosecs, uint64_t start); -#endif /* _UTILS_H_ */ \ No newline at end of file +#endif /* _UTILS_H_ */ From 53f9e72e180e3d9c57b105cf2d0ecbc6730636fa Mon Sep 17 00:00:00 2001 From: Georg Reinke Date: Tue, 28 Mar 2017 13:31:55 +0200 Subject: [PATCH 09/15] Revert "fix IS_ALIGNED macro" This reverts commit 07a3b4db789ec6fe0c4773b9199b268280abc4a3. --- include/villas/utils.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/villas/utils.h b/include/villas/utils.h index 03e6ae686..9df8b9ba9 100644 --- a/include/villas/utils.h +++ b/include/villas/utils.h @@ -51,7 +51,7 @@ #define ALIGN(x, a) ALIGN_MASK(x, (uintptr_t) (a) - 1) #define ALIGN_MASK(x, m) (((uintptr_t) (x) + (m)) & ~(m)) -#define IS_ALIGNED(x, a) ((uintptr_t) (x) % (uintptr_t) (a) == 0) +#define IS_ALIGNED(x, a) (ALIGN(x, a) == (uintptr_t) x) /** Round-up integer division */ #define CEIL(x, y) (((x) + (y) - 1) / (y)) @@ -228,4 +228,4 @@ static inline int log2i(long long x) { /** Sleep with rdtsc */ void rdtsc_sleep(uint64_t nanosecs, uint64_t start); -#endif /* _UTILS_H_ */ +#endif /* _UTILS_H_ */ \ No newline at end of file From f4959f51b7ce2c7fabebffac2e97aa87995a896c Mon Sep 17 00:00:00 2001 From: Georg Reinke Date: Tue, 28 Mar 2017 13:32:17 +0200 Subject: [PATCH 10/15] memtype-managed: fix typo in test --- tests/memory.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/memory.c b/tests/memory.c index c7a9e7931..35a5b34c1 100644 --- a/tests/memory.c +++ b/tests/memory.c @@ -56,7 +56,7 @@ Test(memory, manager) { p3 = memory_alloc_aligned(manager, 128, 256); cr_assert(p3); - cr_assert(IS_ALIGNED(p1, 256)); + cr_assert(IS_ALIGNED(p3, 256)); cr_assert(memory_free(manager, p2, 32) == 0); cr_assert(memory_free(manager, p1, 128) == 0); From 92952f9321fba20df1a14e81a8b7645892fb4c8e Mon Sep 17 00:00:00 2001 From: Georg Reinke Date: Wed, 29 Mar 2017 10:31:56 +0200 Subject: [PATCH 11/15] change comment format --- lib/memory.c | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/lib/memory.c b/lib/memory.c index 5e1ba2e99..eb511431b 100644 --- a/lib/memory.c +++ b/lib/memory.c @@ -105,7 +105,7 @@ static int memory_hugepage_free(struct memtype *m, void *ptr, size_t len) void* memory_managed_alloc(struct memtype *m, size_t len, size_t alignment) { - // Simple first-fit allocation. + /* Simple first-fit allocation */ struct memtype_managed* man = (struct memtype_managed*) m; struct memblock* block; for (block = man->first; block != NULL; block = block->next) { @@ -114,24 +114,24 @@ void* memory_managed_alloc(struct memtype *m, size_t len, size_t alignment) char* cptr = (char*) block + sizeof(struct memblock); size_t avail = block->len; uintptr_t uptr = (uintptr_t) cptr; - // check alignment first; leave a gap at start of block to assure - // alignment if necessary + /* check alignment first; leave a gap at start of block to assure + * alignment if necessary */ uintptr_t rem = uptr % alignment; uintptr_t gap = 0; if (rem != 0) { gap = alignment - rem; if (gap > avail) - // next aligned address isn't in this block anymore + /* next aligned address isn't in this block anymore */ continue; cptr += gap; avail -= gap; } if (avail >= len) { if (gap > sizeof(struct memblock)) { - // the alignment gap is big enough to fit another block. - // the original block descriptor is already at the correct - // position, so we just change its len and create a new block - // descriptor for the actual block we're handling. + /* The alignment gap is big enough to fit another block. + * The original block descriptor is already at the correct + * position, so we just change its len and create a new block + * descriptor for the actual block we're handling. */ block->len = gap; struct memblock *newblock = (struct memblock*) (cptr - sizeof(struct memblock)); newblock->prev = block; @@ -141,12 +141,12 @@ void* memory_managed_alloc(struct memtype *m, size_t len, size_t alignment) newblock->len = len; block = newblock; } else { - // the gap is too small to fit another block descriptor, so we - // must account for the gap length in the block length. + /* The gap is too small to fit another block descriptor, so we + * must account for the gap length in the block length. */ block->len = len + gap; } if (avail > len + sizeof(struct memblock)) { - // imperfect fit, so create another block for the remaining part + /* imperfect fit, so create another block for the remaining part */ struct memblock *newblock = (struct memblock*) (cptr + len); newblock->prev = block; newblock->next = block->next; @@ -156,16 +156,16 @@ void* memory_managed_alloc(struct memtype *m, size_t len, size_t alignment) newblock->flags = 0; newblock->len = avail - len - sizeof(struct memblock); } else { - // if this block was larger than the requested length, but only - // by less than sizeof(struct memblock), we may have wasted - // memory by previous assignments to block->len + /* if this block was larger than the requested length, but only + * by less than sizeof(struct memblock), we may have wasted + * memory by previous assignments to block->len. */ block->len = avail; } block->flags |= MEMBLOCK_USED; return (void*) cptr; } } - // no suitable block found + /* no suitable block found */ return NULL; } @@ -177,14 +177,14 @@ int memory_managed_free(struct memtype *m, void *ptr, size_t len) for (block = man->first; block != NULL; block = block->next) { if (!(block->flags & MEMBLOCK_USED)) continue; - // since we may waste some memory at the start of a block to ensure - // alignment, ptr may not actually be the start of the block + /* since we may waste some memory at the start of a block to ensure + * alignment, ptr may not actually be the start of the block */ if ((char*) block + sizeof(struct memblock) <= cptr && cptr < (char*) block + sizeof(struct memblock) + block->len) { - // try to merge it with neighbouring free blocks + /* try to merge it with neighbouring free blocks */ if (block->prev && !(block->prev->flags & MEMBLOCK_USED) && block->next && !(block->next->flags & MEMBLOCK_USED)) { - // special case first: both previous and next block are unused + /* special case first: both previous and next block are unused */ block->prev->len += block->len + block->next->len + 2 * sizeof(struct memblock); block->prev->next = block->next->next; if (block->next->next) @@ -200,7 +200,7 @@ int memory_managed_free(struct memtype *m, void *ptr, size_t len) if (block->next) block->next->prev = block; } else { - // no neighbouring free block, so just mark it as free + /* no neighbouring free block, so just mark it as free */ block->flags &= (~MEMBLOCK_USED); } return 0; @@ -217,7 +217,7 @@ struct memtype* memtype_managed_init(void *ptr, size_t len) } struct memtype_managed *man = (struct memtype_managed*) ptr; man->mt.name = "managed"; - man->mt.flags = 0; // TODO + man->mt.flags = 0; man->mt.alloc = memory_managed_alloc; man->mt.free = memory_managed_free; man->mt.alignment = 1; From 78f5a3f818d645d3087a8fbee2087f14e1896a72 Mon Sep 17 00:00:00 2001 From: Georg Reinke Date: Wed, 29 Mar 2017 11:29:53 +0200 Subject: [PATCH 12/15] use new _vd element for possible memtype state --- include/villas/memory.h | 15 ++++-------- lib/memory.c | 51 +++++++++++++++++++++-------------------- tests/memory.c | 3 ++- 3 files changed, 33 insertions(+), 36 deletions(-) diff --git a/include/villas/memory.h b/include/villas/memory.h index e1ee37267..99993457f 100644 --- a/include/villas/memory.h +++ b/include/villas/memory.h @@ -33,28 +33,23 @@ struct memtype { memzone_allocator_t alloc; memzone_deallocator_t free; + + void *_vd; /**first; block != NULL; block = block->next) { + struct memblock *first = (struct memblock*) m->_vd; + struct memblock *block; + for (block = first; block != NULL; block = block->next) { if (block->flags & MEMBLOCK_USED) continue; char* cptr = (char*) block + sizeof(struct memblock); @@ -171,10 +171,10 @@ void* memory_managed_alloc(struct memtype *m, size_t len, size_t alignment) int memory_managed_free(struct memtype *m, void *ptr, size_t len) { - struct memtype_managed* man = (struct memtype_managed*) m; + struct memblock *first = m->_vd; + struct memblock *block; char* cptr = (char*) ptr; - struct memblock* block; - for (block = man->first; block != NULL; block = block->next) { + for (block = first; block != NULL; block = block->next) { if (!(block->flags & MEMBLOCK_USED)) continue; /* since we may waste some memory at the start of a block to ensure @@ -211,29 +211,28 @@ int memory_managed_free(struct memtype *m, void *ptr, size_t len) struct memtype* memtype_managed_init(void *ptr, size_t len) { - if (len < sizeof(struct memtype_managed) + sizeof(struct memblock)) { - info("memtype_managed: passed region too small"); + if (len < sizeof(struct memtype) + sizeof(struct memblock)) { + info("memtype_managed_init: passed region too small"); return NULL; } - struct memtype_managed *man = (struct memtype_managed*) ptr; - man->mt.name = "managed"; - man->mt.flags = 0; - man->mt.alloc = memory_managed_alloc; - man->mt.free = memory_managed_free; - man->mt.alignment = 1; - man->base = ptr; - man->len = len; + struct memtype *mt = (struct memtype*) ptr; + mt->name = "managed"; + mt->flags = 0; + mt->alloc = memory_managed_alloc; + mt->free = memory_managed_free; + mt->alignment = 1; char *cptr = (char*) ptr; - cptr += ALIGN(sizeof(struct memtype_managed), sizeof(void*)); - man->first = (struct memblock*) ((void*) cptr); - man->first->prev = NULL; - man->first->next = NULL; + cptr += ALIGN(sizeof(struct memtype), sizeof(void*)); + struct memblock *first = (struct memblock*) ((void*) cptr); + first->prev = NULL; + first->next = NULL; cptr += ALIGN(sizeof(struct memblock), sizeof(void*)); - man->first->len = len - (cptr - (char*) ptr); - man->first->flags = 0; + first->len = len - (cptr - (char*) ptr); + first->flags = 0; + mt->_vd = (void*) first; - return (struct memtype*) man; + return mt; } /* List of available memory types */ @@ -242,7 +241,8 @@ struct memtype memtype_heap = { .flags = MEMORY_HEAP, .alloc = memory_heap_alloc, .free = memory_heap_free, - .alignment = 1 + .alignment = 1, + ._vd = NULL, }; struct memtype memtype_hugepage = { @@ -250,7 +250,8 @@ struct memtype memtype_hugepage = { .flags = MEMORY_MMAP | MEMORY_HUGEPAGE, .alloc = memory_hugepage_alloc, .free = memory_hugepage_free, - .alignment = 21 /* 2 MiB hugepage */ + .alignment = 21, /* 2 MiB hugepage */ + ._vd = NULL, }; /** @todo */ diff --git a/tests/memory.c b/tests/memory.c index 35a5b34c1..1cb57cbc5 100644 --- a/tests/memory.c +++ b/tests/memory.c @@ -37,7 +37,7 @@ Theory((size_t len, size_t align, struct memtype *m), memory, aligned) { Test(memory, manager) { size_t total_size = 1 << 10; - size_t max_block = total_size - sizeof(struct memtype_managed) - sizeof(struct memblock); + size_t max_block = total_size - sizeof(struct memtype) - sizeof(struct memblock); void *p = memory_alloc(&memtype_heap, total_size); struct memtype *manager = memtype_managed_init(p, total_size); @@ -66,4 +66,5 @@ Test(memory, manager) { p1 = memory_alloc(manager, max_block); cr_assert(p1); cr_assert(memory_free(manager, p1, max_block) == 0); + memory_free(&memtype_heap, p, total_size); } From c749821b8d6552f2647a4c9d9721cfdb95f4e906 Mon Sep 17 00:00:00 2001 From: Georg Reinke Date: Wed, 29 Mar 2017 12:00:49 +0200 Subject: [PATCH 13/15] memtype-managed: calculate block lengths correctly --- lib/memory.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/memory.c b/lib/memory.c index e6008303c..fb499d281 100644 --- a/lib/memory.c +++ b/lib/memory.c @@ -132,7 +132,7 @@ void* memory_managed_alloc(struct memtype *m, size_t len, size_t alignment) * The original block descriptor is already at the correct * position, so we just change its len and create a new block * descriptor for the actual block we're handling. */ - block->len = gap; + block->len = gap - sizeof(struct memblock); struct memblock *newblock = (struct memblock*) (cptr - sizeof(struct memblock)); newblock->prev = block; newblock->next = block->next; From b4ba09d9f198474ac05fc6f69bffdaabd0ba590f Mon Sep 17 00:00:00 2001 From: Georg Reinke Date: Wed, 29 Mar 2017 12:05:38 +0200 Subject: [PATCH 14/15] memtype-managed: fix tab/spaces format --- include/villas/memory.h | 12 +- lib/memory.c | 236 ++++++++++++++++++++-------------------- 2 files changed, 124 insertions(+), 124 deletions(-) diff --git a/include/villas/memory.h b/include/villas/memory.h index 99993457f..25f683e20 100644 --- a/include/villas/memory.h +++ b/include/villas/memory.h @@ -34,20 +34,20 @@ struct memtype { memzone_allocator_t alloc; memzone_deallocator_t free; - void *_vd; /**_vd; - struct memblock *block; - for (block = first; block != NULL; block = block->next) { - if (block->flags & MEMBLOCK_USED) - continue; - char* cptr = (char*) block + sizeof(struct memblock); - size_t avail = block->len; - uintptr_t uptr = (uintptr_t) cptr; - /* check alignment first; leave a gap at start of block to assure - * alignment if necessary */ - uintptr_t rem = uptr % alignment; - uintptr_t gap = 0; - if (rem != 0) { - gap = alignment - rem; - if (gap > avail) - /* next aligned address isn't in this block anymore */ - continue; - cptr += gap; - avail -= gap; - } - if (avail >= len) { - if (gap > sizeof(struct memblock)) { - /* The alignment gap is big enough to fit another block. - * The original block descriptor is already at the correct - * position, so we just change its len and create a new block - * descriptor for the actual block we're handling. */ - block->len = gap - sizeof(struct memblock); - struct memblock *newblock = (struct memblock*) (cptr - sizeof(struct memblock)); - newblock->prev = block; - newblock->next = block->next; - block->next = newblock; - newblock->flags = 0; - newblock->len = len; - block = newblock; - } else { - /* The gap is too small to fit another block descriptor, so we - * must account for the gap length in the block length. */ - block->len = len + gap; - } - if (avail > len + sizeof(struct memblock)) { - /* imperfect fit, so create another block for the remaining part */ - struct memblock *newblock = (struct memblock*) (cptr + len); - newblock->prev = block; - newblock->next = block->next; - block->next = newblock; - if (newblock->next) - newblock->next->prev = newblock; - newblock->flags = 0; - newblock->len = avail - len - sizeof(struct memblock); - } else { - /* if this block was larger than the requested length, but only - * by less than sizeof(struct memblock), we may have wasted - * memory by previous assignments to block->len. */ - block->len = avail; - } - block->flags |= MEMBLOCK_USED; - return (void*) cptr; - } - } - /* no suitable block found */ - return NULL; + struct memblock *first = (struct memblock*) m->_vd; + struct memblock *block; + for (block = first; block != NULL; block = block->next) { + if (block->flags & MEMBLOCK_USED) + continue; + char* cptr = (char*) block + sizeof(struct memblock); + size_t avail = block->len; + uintptr_t uptr = (uintptr_t) cptr; + /* check alignment first; leave a gap at start of block to assure + * alignment if necessary */ + uintptr_t rem = uptr % alignment; + uintptr_t gap = 0; + if (rem != 0) { + gap = alignment - rem; + if (gap > avail) + /* next aligned address isn't in this block anymore */ + continue; + cptr += gap; + avail -= gap; + } + if (avail >= len) { + if (gap > sizeof(struct memblock)) { + /* The alignment gap is big enough to fit another block. + * The original block descriptor is already at the correct + * position, so we just change its len and create a new block + * descriptor for the actual block we're handling. */ + block->len = gap - sizeof(struct memblock); + struct memblock *newblock = (struct memblock*) (cptr - sizeof(struct memblock)); + newblock->prev = block; + newblock->next = block->next; + block->next = newblock; + newblock->flags = 0; + newblock->len = len; + block = newblock; + } else { + /* The gap is too small to fit another block descriptor, so we + * must account for the gap length in the block length. */ + block->len = len + gap; + } + if (avail > len + sizeof(struct memblock)) { + /* imperfect fit, so create another block for the remaining part */ + struct memblock *newblock = (struct memblock*) (cptr + len); + newblock->prev = block; + newblock->next = block->next; + block->next = newblock; + if (newblock->next) + newblock->next->prev = newblock; + newblock->flags = 0; + newblock->len = avail - len - sizeof(struct memblock); + } else { + /* if this block was larger than the requested length, but only + * by less than sizeof(struct memblock), we may have wasted + * memory by previous assignments to block->len. */ + block->len = avail; + } + block->flags |= MEMBLOCK_USED; + return (void*) cptr; + } + } + /* no suitable block found */ + return NULL; } int memory_managed_free(struct memtype *m, void *ptr, size_t len) { - struct memblock *first = m->_vd; - struct memblock *block; - char* cptr = (char*) ptr; - for (block = first; block != NULL; block = block->next) { - if (!(block->flags & MEMBLOCK_USED)) - continue; - /* since we may waste some memory at the start of a block to ensure - * alignment, ptr may not actually be the start of the block */ - if ((char*) block + sizeof(struct memblock) <= cptr && - cptr < (char*) block + sizeof(struct memblock) + block->len) { - /* try to merge it with neighbouring free blocks */ - if (block->prev && !(block->prev->flags & MEMBLOCK_USED) && - block->next && !(block->next->flags & MEMBLOCK_USED)) { - /* special case first: both previous and next block are unused */ - block->prev->len += block->len + block->next->len + 2 * sizeof(struct memblock); - block->prev->next = block->next->next; - if (block->next->next) - block->next->next->prev = block->prev; - } else if (block->prev && !(block->prev->flags & MEMBLOCK_USED)) { - block->prev->len += block->len + sizeof(struct memblock); - block->prev->next = block->next; - if (block->next) - block->next->prev = block->prev; - } else if (block->next && !(block->next->flags & MEMBLOCK_USED)) { - block->len += block->next->len + sizeof(struct memblock); - block->next = block->next->next; - if (block->next) - block->next->prev = block; - } else { - /* no neighbouring free block, so just mark it as free */ - block->flags &= (~MEMBLOCK_USED); - } - return 0; - } - } - return -1; + struct memblock *first = m->_vd; + struct memblock *block; + char* cptr = (char*) ptr; + for (block = first; block != NULL; block = block->next) { + if (!(block->flags & MEMBLOCK_USED)) + continue; + /* since we may waste some memory at the start of a block to ensure + * alignment, ptr may not actually be the start of the block */ + if ((char*) block + sizeof(struct memblock) <= cptr && + cptr < (char*) block + sizeof(struct memblock) + block->len) { + /* try to merge it with neighbouring free blocks */ + if (block->prev && !(block->prev->flags & MEMBLOCK_USED) && + block->next && !(block->next->flags & MEMBLOCK_USED)) { + /* special case first: both previous and next block are unused */ + block->prev->len += block->len + block->next->len + 2 * sizeof(struct memblock); + block->prev->next = block->next->next; + if (block->next->next) + block->next->next->prev = block->prev; + } else if (block->prev && !(block->prev->flags & MEMBLOCK_USED)) { + block->prev->len += block->len + sizeof(struct memblock); + block->prev->next = block->next; + if (block->next) + block->next->prev = block->prev; + } else if (block->next && !(block->next->flags & MEMBLOCK_USED)) { + block->len += block->next->len + sizeof(struct memblock); + block->next = block->next->next; + if (block->next) + block->next->prev = block; + } else { + /* no neighbouring free block, so just mark it as free */ + block->flags &= (~MEMBLOCK_USED); + } + return 0; + } + } + return -1; } struct memtype* memtype_managed_init(void *ptr, size_t len) { - if (len < sizeof(struct memtype) + sizeof(struct memblock)) { - info("memtype_managed_init: passed region too small"); - return NULL; - } - struct memtype *mt = (struct memtype*) ptr; - mt->name = "managed"; - mt->flags = 0; - mt->alloc = memory_managed_alloc; - mt->free = memory_managed_free; - mt->alignment = 1; + if (len < sizeof(struct memtype) + sizeof(struct memblock)) { + info("memtype_managed_init: passed region too small"); + return NULL; + } + struct memtype *mt = (struct memtype*) ptr; + mt->name = "managed"; + mt->flags = 0; + mt->alloc = memory_managed_alloc; + mt->free = memory_managed_free; + mt->alignment = 1; - char *cptr = (char*) ptr; - cptr += ALIGN(sizeof(struct memtype), sizeof(void*)); - struct memblock *first = (struct memblock*) ((void*) cptr); - first->prev = NULL; - first->next = NULL; - cptr += ALIGN(sizeof(struct memblock), sizeof(void*)); - first->len = len - (cptr - (char*) ptr); - first->flags = 0; - mt->_vd = (void*) first; + char *cptr = (char*) ptr; + cptr += ALIGN(sizeof(struct memtype), sizeof(void*)); + struct memblock *first = (struct memblock*) ((void*) cptr); + first->prev = NULL; + first->next = NULL; + cptr += ALIGN(sizeof(struct memblock), sizeof(void*)); + first->len = len - (cptr - (char*) ptr); + first->flags = 0; + mt->_vd = (void*) first; - return mt; + return mt; } /* List of available memory types */ @@ -242,7 +242,7 @@ struct memtype memtype_heap = { .alloc = memory_heap_alloc, .free = memory_heap_free, .alignment = 1, - ._vd = NULL, + ._vd = NULL, }; struct memtype memtype_hugepage = { From bb745ea048df17c985539b8d9838996ff95cfb56 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Fri, 31 Mar 2017 18:04:08 +0200 Subject: [PATCH 15/15] cosmetic changes (indentions, whitesapces, naming) --- include/villas/memory.h | 2 +- lib/memory.c | 142 ++++++++++++++++++++++------------------ 2 files changed, 80 insertions(+), 64 deletions(-) diff --git a/include/villas/memory.h b/include/villas/memory.h index 25f683e20..48e98b7a0 100644 --- a/include/villas/memory.h +++ b/include/villas/memory.h @@ -73,7 +73,7 @@ void * memory_alloc_aligned(struct memtype *m, size_t len, size_t alignment); int memory_free(struct memtype *m, void *ptr, size_t len); -struct memtype* memtype_managed_init(void *ptr, size_t len); +struct memtype * memtype_managed_init(void *ptr, size_t len); extern struct memtype memtype_heap; extern struct memtype memtype_hugepage; diff --git a/lib/memory.c b/lib/memory.c index 7bbd6de9f..52abd3fb2 100644 --- a/lib/memory.c +++ b/lib/memory.c @@ -21,9 +21,9 @@ int memory_init() { #ifdef __linux__ int nr = kernel_get_nr_hugepages(); - + debug(DBG_MEM | 2, "System has %d reserved hugepages", nr); - + if (nr < DEFAULT_NR_HUGEPAGES) kernel_set_nr_hugepages(DEFAULT_NR_HUGEPAGES); #endif @@ -33,7 +33,7 @@ int memory_init() void * memory_alloc(struct memtype *m, size_t len) { void *ptr = m->alloc(m, len, sizeof(void *)); - + debug(DBG_MEM | 2, "Allocated %#zx bytes of %s memory: %p", len, m->name, ptr); return ptr; @@ -42,9 +42,9 @@ void * memory_alloc(struct memtype *m, size_t len) void * memory_alloc_aligned(struct memtype *m, size_t len, size_t alignment) { void *ptr = m->alloc(m, len, alignment); - + debug(DBG_MEM | 2, "Allocated %#zx bytes of %#zx-byte-aligned %s memory: %p", len, alignment, m->name, ptr); - + return ptr; } @@ -58,19 +58,19 @@ static void * memory_heap_alloc(struct memtype *m, size_t len, size_t alignment) { void *ptr; int ret; - + if (alignment < sizeof(void *)) alignment = sizeof(void *); - + ret = posix_memalign(&ptr, alignment, len); - + return ret ? NULL : ptr; } int memory_heap_free(struct memtype *m, void *ptr, size_t len) { free(ptr); - + return 0; } @@ -79,20 +79,20 @@ static void * memory_hugepage_alloc(struct memtype *m, size_t len, size_t alignm { int prot = PROT_READ | PROT_WRITE; int flags = MAP_PRIVATE | MAP_ANONYMOUS; - + #ifdef __MACH__ flags |= VM_FLAGS_SUPERPAGE_SIZE_2MB; #elif defined(__linux__) flags |= MAP_HUGETLB | MAP_LOCKED; #endif - + void *ret = mmap(NULL, len, prot, flags, -1, 0); - + if (ret == MAP_FAILED) { info("Failed to allocate huge pages: Check https://www.kernel.org/doc/Documentation/vm/hugetlbpage.txt"); return NULL; } - + return ret; } @@ -105,27 +105,31 @@ static int memory_hugepage_free(struct memtype *m, void *ptr, size_t len) void* memory_managed_alloc(struct memtype *m, size_t len, size_t alignment) { - /* Simple first-fit allocation */ - struct memblock *first = (struct memblock*) m->_vd; + /* Simple first-fit allocation */ + struct memblock *first = m->_vd; struct memblock *block; + for (block = first; block != NULL; block = block->next) { if (block->flags & MEMBLOCK_USED) continue; - char* cptr = (char*) block + sizeof(struct memblock); + + char* cptr = (char *) block + sizeof(struct memblock); size_t avail = block->len; uintptr_t uptr = (uintptr_t) cptr; - /* check alignment first; leave a gap at start of block to assure + + /* Check alignment first; leave a gap at start of block to assure * alignment if necessary */ uintptr_t rem = uptr % alignment; uintptr_t gap = 0; if (rem != 0) { gap = alignment - rem; if (gap > avail) - /* next aligned address isn't in this block anymore */ - continue; + continue; /* Next aligned address isn't in this block anymore */ + cptr += gap; avail -= gap; } + if (avail >= len) { if (gap > sizeof(struct memblock)) { /* The alignment gap is big enough to fit another block. @@ -133,21 +137,23 @@ void* memory_managed_alloc(struct memtype *m, size_t len, size_t alignment) * position, so we just change its len and create a new block * descriptor for the actual block we're handling. */ block->len = gap - sizeof(struct memblock); - struct memblock *newblock = (struct memblock*) (cptr - sizeof(struct memblock)); + struct memblock *newblock = (struct memblock *) (cptr - sizeof(struct memblock)); newblock->prev = block; newblock->next = block->next; block->next = newblock; newblock->flags = 0; newblock->len = len; block = newblock; - } else { + } + else { /* The gap is too small to fit another block descriptor, so we * must account for the gap length in the block length. */ block->len = len + gap; } + if (avail > len + sizeof(struct memblock)) { - /* imperfect fit, so create another block for the remaining part */ - struct memblock *newblock = (struct memblock*) (cptr + len); + /* Imperfect fit, so create another block for the remaining part */ + struct memblock *newblock = (struct memblock *) (cptr + len); newblock->prev = block; newblock->next = block->next; block->next = newblock; @@ -155,17 +161,21 @@ void* memory_managed_alloc(struct memtype *m, size_t len, size_t alignment) newblock->next->prev = newblock; newblock->flags = 0; newblock->len = avail - len - sizeof(struct memblock); - } else { - /* if this block was larger than the requested length, but only + } + else { + /* If this block was larger than the requested length, but only * by less than sizeof(struct memblock), we may have wasted * memory by previous assignments to block->len. */ block->len = avail; } + block->flags |= MEMBLOCK_USED; - return (void*) cptr; + + return (void *) cptr; } } - /* no suitable block found */ + + /* No suitable block found */ return NULL; } @@ -173,64 +183,80 @@ int memory_managed_free(struct memtype *m, void *ptr, size_t len) { struct memblock *first = m->_vd; struct memblock *block; - char* cptr = (char*) ptr; + char *cptr = ptr; + for (block = first; block != NULL; block = block->next) { if (!(block->flags & MEMBLOCK_USED)) continue; - /* since we may waste some memory at the start of a block to ensure + + /* Since we may waste some memory at the start of a block to ensure * alignment, ptr may not actually be the start of the block */ - if ((char*) block + sizeof(struct memblock) <= cptr && - cptr < (char*) block + sizeof(struct memblock) + block->len) { - /* try to merge it with neighbouring free blocks */ + if ((char *) block + sizeof(struct memblock) <= cptr && + cptr < (char *) block + sizeof(struct memblock) + block->len) { + /* Try to merge it with neighbouring free blocks */ if (block->prev && !(block->prev->flags & MEMBLOCK_USED) && block->next && !(block->next->flags & MEMBLOCK_USED)) { - /* special case first: both previous and next block are unused */ + /* Special case first: both previous and next block are unused */ block->prev->len += block->len + block->next->len + 2 * sizeof(struct memblock); block->prev->next = block->next->next; if (block->next->next) block->next->next->prev = block->prev; - } else if (block->prev && !(block->prev->flags & MEMBLOCK_USED)) { + } + else if (block->prev && !(block->prev->flags & MEMBLOCK_USED)) { block->prev->len += block->len + sizeof(struct memblock); block->prev->next = block->next; if (block->next) block->next->prev = block->prev; - } else if (block->next && !(block->next->flags & MEMBLOCK_USED)) { + } + else if (block->next && !(block->next->flags & MEMBLOCK_USED)) { block->len += block->next->len + sizeof(struct memblock); block->next = block->next->next; if (block->next) block->next->prev = block; - } else { - /* no neighbouring free block, so just mark it as free */ - block->flags &= (~MEMBLOCK_USED); } + else { + /* no neighbouring free block, so just mark it as free */ + block->flags &= ~MEMBLOCK_USED; + } + return 0; } } + return -1; } -struct memtype* memtype_managed_init(void *ptr, size_t len) +struct memtype * memtype_managed_init(void *ptr, size_t len) { + struct memtype *mt = ptr; + struct memblock *mb; + char *cptr = ptr; + if (len < sizeof(struct memtype) + sizeof(struct memblock)) { info("memtype_managed_init: passed region too small"); return NULL; } - struct memtype *mt = (struct memtype*) ptr; - mt->name = "managed"; + + /* Initialize memtype */ + mt->name = "managed"; mt->flags = 0; mt->alloc = memory_managed_alloc; - mt->free = memory_managed_free; + mt->free = memory_managed_free; mt->alignment = 1; - char *cptr = (char*) ptr; - cptr += ALIGN(sizeof(struct memtype), sizeof(void*)); - struct memblock *first = (struct memblock*) ((void*) cptr); - first->prev = NULL; - first->next = NULL; - cptr += ALIGN(sizeof(struct memblock), sizeof(void*)); - first->len = len - (cptr - (char*) ptr); - first->flags = 0; - mt->_vd = (void*) first; + cptr += ALIGN(sizeof(struct memtype), sizeof(void *)); + + /* Initialize first free memblock */ + mb = (struct memblock *) cptr; + mb->prev = NULL; + mb->next = NULL; + mb->flags = 0; + + cptr += ALIGN(sizeof(struct memblock), sizeof(void *)); + + mb->len = len - (cptr - (char *) ptr); + + mt->_vd = (void *) mb; return mt; } @@ -241,8 +267,7 @@ struct memtype memtype_heap = { .flags = MEMORY_HEAP, .alloc = memory_heap_alloc, .free = memory_heap_free, - .alignment = 1, - ._vd = NULL, + .alignment = 1 }; struct memtype memtype_hugepage = { @@ -250,14 +275,5 @@ struct memtype memtype_hugepage = { .flags = MEMORY_MMAP | MEMORY_HUGEPAGE, .alloc = memory_hugepage_alloc, .free = memory_hugepage_free, - .alignment = 21, /* 2 MiB hugepage */ - ._vd = NULL, -}; - -/** @todo */ -const struct memtype memtype_dma = { - .name = "dma", - .flags = MEMORY_DMA | MEMORY_MMAP, - .alloc = NULL, .free = NULL, - .alignment = 12 + .alignment = 21 /* 2 MiB hugepage */ };