Loading src/common/mempool.c +74 −5 Original line number Diff line number Diff line Loading @@ -56,6 +56,8 @@ /** DOCDOC */ #define MIN_CHUNK 4096 typedef struct mp_allocated_t mp_allocated_t; /** DOCDOC */ struct mp_allocated_t { mp_chunk_t *in_chunk; Loading @@ -66,6 +68,20 @@ struct mp_allocated_t { }; }; /** DOCDOC */ struct mp_chunk_t { unsigned long magic; mp_chunk_t *next; mp_chunk_t *prev; mp_pool_t *pool; mp_allocated_t *first_free; int n_allocated; int capacity; size_t mem_size; char *next_mem; char mem[1]; }; /** DOCDOC */ #define MP_CHUNK_MAGIC 0x09870123 Loading @@ -73,9 +89,9 @@ struct mp_allocated_t { #define CHUNK_OVERHEAD (sizeof(mp_chunk_t)-1) /** DOCDOC */ #define A2M(a) (&(a)->mem) #define A2M(a) (&(a)->mem[0]) /** DOCDOC */ #define M2A(p) ( ((char*)p) - STRUCT_OFFSET(mp_chunk_t, mem) ) #define M2A(p) ( ((char*)p) - STRUCT_OFFSET(mp_allocated_t, mem) ) /* INVARIANT: every chunk can hold 2 or more items. */ Loading Loading @@ -113,6 +129,7 @@ mp_pool_get(mp_pool_t *pool) chunk->next->prev = chunk; pool->used_chunks = chunk; ASSERT(!chunk->prev); --pool->n_empty_chunks; } else { /* Allocate a new chunk and add it to the used list. */ chunk = mp_chunk_new(pool); Loading @@ -130,7 +147,7 @@ mp_pool_get(mp_pool_t *pool) chunk->first_free = allocated->next_free; allocated->next_free = NULL; /* debugging */ } else { ASSERT(chunk->next_mem + pool->item_alloc_size < ASSERT(chunk->next_mem + pool->item_alloc_size <= chunk->mem + chunk->mem_size); allocated = (void*)chunk->next_mem; chunk->next_mem += pool->item_alloc_size; Loading @@ -147,7 +164,8 @@ mp_pool_get(mp_pool_t *pool) chunk->next->prev = NULL; chunk->next = pool->full_chunks; pool->full_chunks->prev = chunk; if (chunk->next) chunk->next->prev = chunk; pool->full_chunks = chunk; } Loading Loading @@ -245,7 +263,7 @@ mp_pool_new(size_t item_size, size_t chunk_capacity) if (chunk_capacity < MIN_CHUNK) /* Guess system page size. */ chunk_capacity = MIN_CHUNK; pool->new_chunk_capacity = (chunk_capacity-CHUNK_OVERHEAD / alloc_size); pool->new_chunk_capacity = (chunk_capacity-CHUNK_OVERHEAD) / alloc_size; pool->item_alloc_size = alloc_size; return pool; Loading Loading @@ -291,3 +309,54 @@ mp_pool_destroy(mp_pool_t *pool) FREE(pool); } static int assert_chunks_ok(mp_pool_t *pool, mp_chunk_t *chunk, int empty, int full) { mp_allocated_t *allocated; int n = 0; if (chunk) ASSERT(chunk->prev == NULL); while (chunk) { n++; ASSERT(chunk->magic == MP_CHUNK_MAGIC); ASSERT(chunk->pool == pool); for (allocated = chunk->first_free; allocated; allocated = allocated->next_free) { ASSERT(allocated->in_chunk == chunk); } if (empty) ASSERT(chunk->n_allocated == 0); else if (full) ASSERT(chunk->n_allocated == chunk->capacity); else ASSERT(chunk->n_allocated > 0 && chunk->n_allocated < chunk->capacity); ASSERT(chunk->capacity == pool->new_chunk_capacity); ASSERT(chunk->mem_size == pool->new_chunk_capacity * pool->item_alloc_size); ASSERT(chunk->next_mem >= chunk->mem && chunk->next_mem <= chunk->mem + chunk->mem_size); if (chunk->next) ASSERT(chunk->next->prev == chunk); chunk = chunk->next; } return n; } void mp_pool_assert_ok(mp_pool_t *pool) { int n_empty; n_empty = assert_chunks_ok(pool, pool->empty_chunks, 1, 0); assert_chunks_ok(pool, pool->full_chunks, 0, 1); assert_chunks_ok(pool, pool->used_chunks, 0, 0); ASSERT(pool->n_empty_chunks == n_empty); } src/common/mempool.h +2 −16 Original line number Diff line number Diff line Loading @@ -17,32 +17,18 @@ void mp_pool_release(void *item); mp_pool_t *mp_pool_new(size_t item_size, unsigned int n_per_chunk); void mp_pool_clean(mp_pool_t *pool); void mp_pool_destroy(mp_pool_t *pool); void mp_pool_assert_ok(mp_pool_t *pool); #ifdef MEMPOOL_PRIVATE typedef struct mp_allocated_t mp_allocated_t; typedef struct mp_chunk_t mp_chunk_t; /** DOCDOC */ struct mp_chunk_t { unsigned long magic; mp_chunk_t *next; mp_chunk_t *prev; mp_pool_t *pool; mp_allocated_t *first_free; int n_allocated; int capacity; size_t mem_size; char *next_mem; char mem[1]; }; /** DOCDOC */ struct mp_pool_t { mp_chunk_t *empty_chunks; mp_chunk_t *used_chunks; mp_chunk_t *full_chunks; int n_empty_chunks; size_t new_chunk_capacity; int new_chunk_capacity; size_t item_alloc_size; }; #endif Loading src/or/test.c +50 −0 Original line number Diff line number Diff line Loading @@ -23,9 +23,12 @@ const char test_c_id[] = #include <dirent.h> #endif #define MEMPOOL_PRIVATE #include "or.h" #include "../common/test.h" #include "../common/torgzip.h" #include "../common/mempool.h" int have_failed = 0; Loading Loading @@ -2104,6 +2107,52 @@ bench_aes(void) crypto_free_cipher_env(c); } static void test_mempool(void) { mp_pool_t *pool; smartlist_t *allocated; int i; pool = mp_pool_new(1, 100); test_assert(pool->new_chunk_capacity >= 100); test_assert(pool->item_alloc_size >= sizeof(void*)+1); mp_pool_destroy(pool); pool = mp_pool_new(241, 10); test_assert(pool->new_chunk_capacity >= 10); test_assert(pool->item_alloc_size >= sizeof(void*)+241); test_eq(pool->item_alloc_size & 0x03, 0); test_assert(pool->new_chunk_capacity < 60); allocated = smartlist_create(); for (i = 0; i < 100000; ++i) { if (smartlist_len(allocated) < 20 || crypto_rand_int(2)) { void *m = mp_pool_get(pool); memset(m, 0x09, 241); smartlist_add(allocated, m); //printf("%d: %p\n", i, m); //mp_pool_assert_ok(pool); } else { int idx = crypto_rand_int(smartlist_len(allocated)); void *m = smartlist_get(allocated, idx); //printf("%d: free %p\n", i, m); smartlist_del(allocated, idx); mp_pool_release(m); //mp_pool_assert_ok(pool); } if (crypto_rand_int(777)==0) mp_pool_clean(pool); if (i % 777) mp_pool_assert_ok(pool); } SMARTLIST_FOREACH(allocated, void *, m, mp_pool_release(m)); mp_pool_assert_ok(pool); mp_pool_destroy(pool); smartlist_free(allocated); } int main(int c, char**v) { Loading Loading @@ -2145,6 +2194,7 @@ main(int c, char**v) test_gzip(); test_util(); test_smartlist(); test_mempool(); test_strmap(); test_control_formats(); test_pqueue(); Loading Loading
src/common/mempool.c +74 −5 Original line number Diff line number Diff line Loading @@ -56,6 +56,8 @@ /** DOCDOC */ #define MIN_CHUNK 4096 typedef struct mp_allocated_t mp_allocated_t; /** DOCDOC */ struct mp_allocated_t { mp_chunk_t *in_chunk; Loading @@ -66,6 +68,20 @@ struct mp_allocated_t { }; }; /** DOCDOC */ struct mp_chunk_t { unsigned long magic; mp_chunk_t *next; mp_chunk_t *prev; mp_pool_t *pool; mp_allocated_t *first_free; int n_allocated; int capacity; size_t mem_size; char *next_mem; char mem[1]; }; /** DOCDOC */ #define MP_CHUNK_MAGIC 0x09870123 Loading @@ -73,9 +89,9 @@ struct mp_allocated_t { #define CHUNK_OVERHEAD (sizeof(mp_chunk_t)-1) /** DOCDOC */ #define A2M(a) (&(a)->mem) #define A2M(a) (&(a)->mem[0]) /** DOCDOC */ #define M2A(p) ( ((char*)p) - STRUCT_OFFSET(mp_chunk_t, mem) ) #define M2A(p) ( ((char*)p) - STRUCT_OFFSET(mp_allocated_t, mem) ) /* INVARIANT: every chunk can hold 2 or more items. */ Loading Loading @@ -113,6 +129,7 @@ mp_pool_get(mp_pool_t *pool) chunk->next->prev = chunk; pool->used_chunks = chunk; ASSERT(!chunk->prev); --pool->n_empty_chunks; } else { /* Allocate a new chunk and add it to the used list. */ chunk = mp_chunk_new(pool); Loading @@ -130,7 +147,7 @@ mp_pool_get(mp_pool_t *pool) chunk->first_free = allocated->next_free; allocated->next_free = NULL; /* debugging */ } else { ASSERT(chunk->next_mem + pool->item_alloc_size < ASSERT(chunk->next_mem + pool->item_alloc_size <= chunk->mem + chunk->mem_size); allocated = (void*)chunk->next_mem; chunk->next_mem += pool->item_alloc_size; Loading @@ -147,7 +164,8 @@ mp_pool_get(mp_pool_t *pool) chunk->next->prev = NULL; chunk->next = pool->full_chunks; pool->full_chunks->prev = chunk; if (chunk->next) chunk->next->prev = chunk; pool->full_chunks = chunk; } Loading Loading @@ -245,7 +263,7 @@ mp_pool_new(size_t item_size, size_t chunk_capacity) if (chunk_capacity < MIN_CHUNK) /* Guess system page size. */ chunk_capacity = MIN_CHUNK; pool->new_chunk_capacity = (chunk_capacity-CHUNK_OVERHEAD / alloc_size); pool->new_chunk_capacity = (chunk_capacity-CHUNK_OVERHEAD) / alloc_size; pool->item_alloc_size = alloc_size; return pool; Loading Loading @@ -291,3 +309,54 @@ mp_pool_destroy(mp_pool_t *pool) FREE(pool); } static int assert_chunks_ok(mp_pool_t *pool, mp_chunk_t *chunk, int empty, int full) { mp_allocated_t *allocated; int n = 0; if (chunk) ASSERT(chunk->prev == NULL); while (chunk) { n++; ASSERT(chunk->magic == MP_CHUNK_MAGIC); ASSERT(chunk->pool == pool); for (allocated = chunk->first_free; allocated; allocated = allocated->next_free) { ASSERT(allocated->in_chunk == chunk); } if (empty) ASSERT(chunk->n_allocated == 0); else if (full) ASSERT(chunk->n_allocated == chunk->capacity); else ASSERT(chunk->n_allocated > 0 && chunk->n_allocated < chunk->capacity); ASSERT(chunk->capacity == pool->new_chunk_capacity); ASSERT(chunk->mem_size == pool->new_chunk_capacity * pool->item_alloc_size); ASSERT(chunk->next_mem >= chunk->mem && chunk->next_mem <= chunk->mem + chunk->mem_size); if (chunk->next) ASSERT(chunk->next->prev == chunk); chunk = chunk->next; } return n; } void mp_pool_assert_ok(mp_pool_t *pool) { int n_empty; n_empty = assert_chunks_ok(pool, pool->empty_chunks, 1, 0); assert_chunks_ok(pool, pool->full_chunks, 0, 1); assert_chunks_ok(pool, pool->used_chunks, 0, 0); ASSERT(pool->n_empty_chunks == n_empty); }
src/common/mempool.h +2 −16 Original line number Diff line number Diff line Loading @@ -17,32 +17,18 @@ void mp_pool_release(void *item); mp_pool_t *mp_pool_new(size_t item_size, unsigned int n_per_chunk); void mp_pool_clean(mp_pool_t *pool); void mp_pool_destroy(mp_pool_t *pool); void mp_pool_assert_ok(mp_pool_t *pool); #ifdef MEMPOOL_PRIVATE typedef struct mp_allocated_t mp_allocated_t; typedef struct mp_chunk_t mp_chunk_t; /** DOCDOC */ struct mp_chunk_t { unsigned long magic; mp_chunk_t *next; mp_chunk_t *prev; mp_pool_t *pool; mp_allocated_t *first_free; int n_allocated; int capacity; size_t mem_size; char *next_mem; char mem[1]; }; /** DOCDOC */ struct mp_pool_t { mp_chunk_t *empty_chunks; mp_chunk_t *used_chunks; mp_chunk_t *full_chunks; int n_empty_chunks; size_t new_chunk_capacity; int new_chunk_capacity; size_t item_alloc_size; }; #endif Loading
src/or/test.c +50 −0 Original line number Diff line number Diff line Loading @@ -23,9 +23,12 @@ const char test_c_id[] = #include <dirent.h> #endif #define MEMPOOL_PRIVATE #include "or.h" #include "../common/test.h" #include "../common/torgzip.h" #include "../common/mempool.h" int have_failed = 0; Loading Loading @@ -2104,6 +2107,52 @@ bench_aes(void) crypto_free_cipher_env(c); } static void test_mempool(void) { mp_pool_t *pool; smartlist_t *allocated; int i; pool = mp_pool_new(1, 100); test_assert(pool->new_chunk_capacity >= 100); test_assert(pool->item_alloc_size >= sizeof(void*)+1); mp_pool_destroy(pool); pool = mp_pool_new(241, 10); test_assert(pool->new_chunk_capacity >= 10); test_assert(pool->item_alloc_size >= sizeof(void*)+241); test_eq(pool->item_alloc_size & 0x03, 0); test_assert(pool->new_chunk_capacity < 60); allocated = smartlist_create(); for (i = 0; i < 100000; ++i) { if (smartlist_len(allocated) < 20 || crypto_rand_int(2)) { void *m = mp_pool_get(pool); memset(m, 0x09, 241); smartlist_add(allocated, m); //printf("%d: %p\n", i, m); //mp_pool_assert_ok(pool); } else { int idx = crypto_rand_int(smartlist_len(allocated)); void *m = smartlist_get(allocated, idx); //printf("%d: free %p\n", i, m); smartlist_del(allocated, idx); mp_pool_release(m); //mp_pool_assert_ok(pool); } if (crypto_rand_int(777)==0) mp_pool_clean(pool); if (i % 777) mp_pool_assert_ok(pool); } SMARTLIST_FOREACH(allocated, void *, m, mp_pool_release(m)); mp_pool_assert_ok(pool); mp_pool_destroy(pool); smartlist_free(allocated); } int main(int c, char**v) { Loading Loading @@ -2145,6 +2194,7 @@ main(int c, char**v) test_gzip(); test_util(); test_smartlist(); test_mempool(); test_strmap(); test_control_formats(); test_pqueue(); Loading