aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2023-07-17 09:06:14 -0700
committer3gg <3gg@shellblade.net>2023-07-17 09:06:14 -0700
commitced89ff7989fde2f3d1828c9be70600d70d72e3d (patch)
tree8c27f6243325f090b08e678e5e28b2055adffcef
parent7ab7d7d5b836d2595c5dc2c6db90c489f6768246 (diff)
Add used list to mempool; fix mem iteration.
-rw-r--r--mem/include/mem.h24
-rw-r--r--mempool/include/mempool.h35
-rw-r--r--mempool/src/mempool.c35
3 files changed, 58 insertions, 36 deletions
diff --git a/mem/include/mem.h b/mem/include/mem.h
index b3d9157..bcff39f 100644
--- a/mem/include/mem.h
+++ b/mem/include/mem.h
@@ -92,17 +92,19 @@
92/// The caller can use 'i' as the index of the current chunk. 92/// The caller can use 'i' as the index of the current chunk.
93/// 93///
94/// It is valid to mem_free() the chunk at each step of the iteration. 94/// It is valid to mem_free() the chunk at each step of the iteration.
95#define mem_foreach(MEM, ITER, BODY) \ 95#define mem_foreach(MEM, ITER, BODY) \
96 size_t i = 0; \ 96 { \
97 do { \ 97 size_t i = 0; \
98 if ((MEM)->mem.chunks[i].used) { \ 98 do { \
99 __typeof__((MEM)->object[0])* ITER = \ 99 if ((MEM)->mem.chunks[i].used) { \
100 &(((__typeof__((MEM)->object[0])*)(MEM)->mem.blocks))[i]; \ 100 __typeof__((MEM)->object[0])* ITER = \
101 (void)ITER; \ 101 &(((__typeof__((MEM)->object[0])*)(MEM)->mem.blocks))[i]; \
102 BODY; \ 102 (void)ITER; \
103 } \ 103 BODY; \
104 i = (MEM)->chunks[i].next; \ 104 } \
105 } while (i); 105 i = (MEM)->mem.chunks[i].next; \
106 } while (i); \
107 }
106 108
107// ----------------------------------------------------------------------------- 109// -----------------------------------------------------------------------------
108 110
diff --git a/mempool/include/mempool.h b/mempool/include/mempool.h
index 23786b3..bd4d4dd 100644
--- a/mempool/include/mempool.h
+++ b/mempool/include/mempool.h
@@ -91,28 +91,43 @@
91/// The caller can use 'i' as the index of the current block. 91/// The caller can use 'i' as the index of the current block.
92/// 92///
93/// It is valid to mempool_free() the object at each step of the iteration. 93/// It is valid to mempool_free() the object at each step of the iteration.
94#define mempool_foreach(POOL, ITER, BODY) \ 94#define mempool_foreach(POOL, ITER, BODY) \
95 for (size_t i = 0; i < (POOL)->pool.num_blocks; ++i) { \ 95 { \
96 if (!(POOL)->pool.block_info[i].used) { \ 96 size_t i = (POOL)->pool.used; \
97 continue; \ 97 do { \
98 } \ 98 if ((POOL)->pool.block_info[i].used) { \
99 __typeof__((POOL)->object[0])* ITER = \ 99 __typeof__((POOL)->object[0])* ITER = \
100 &(((__typeof__((POOL)->object[0])*)(POOL)->pool.blocks))[i]; \ 100 &(((__typeof__((POOL)->object[0])*)(POOL)->pool.blocks))[i]; \
101 (void)ITER; \ 101 (void)ITER; \
102 BODY; \ 102 BODY; \
103 } \
104 const size_t next = (POOL)->pool.block_info[i].next_used; \
105 if (next == i) { \
106 break; \
107 } \
108 i = next; \
109 } while (true); \
103 } 110 }
104 111
105// ----------------------------------------------------------------------------- 112// -----------------------------------------------------------------------------
106 113
107typedef struct BlockInfo { 114typedef struct BlockInfo {
108 size_t next; /// For free blocks, points to the next free block. 115 size_t next_free; /// For free blocks, points to the next free block.
116 size_t next_used; /// For used blocks, points to the next used block.
109 bool used; 117 bool used;
110} BlockInfo; 118} BlockInfo;
111 119
120/// Memory pool.
121///
122/// 'head' and 'used' always points to a valid block (e.g., 0).
123/// The implementation must check whether the head of the lists are used/free.
124/// For example, iteration must stop when it finds the first unused block
125/// (BlockInfo.used == 0).
112typedef struct mempool { 126typedef struct mempool {
113 size_t block_size_bytes; 127 size_t block_size_bytes;
114 size_t num_blocks; 128 size_t num_blocks;
115 size_t head; /// Points to the first block in the free list. 129 size_t head; /// Points to the first block in the free list.
130 size_t used; /// Points to the first block in the used list.
116 bool dynamic; /// True if blocks and info are dynamically-allocated. 131 bool dynamic; /// True if blocks and info are dynamically-allocated.
117 BlockInfo* block_info; 132 BlockInfo* block_info;
118 uint8_t* blocks; 133 uint8_t* blocks;
diff --git a/mempool/src/mempool.c b/mempool/src/mempool.c
index 679f124..1100dad 100644
--- a/mempool/src/mempool.c
+++ b/mempool/src/mempool.c
@@ -3,18 +3,14 @@
3#include <stdlib.h> 3#include <stdlib.h>
4#include <string.h> 4#include <string.h>
5 5
6#define NO_BLOCK ((size_t)-1)
7
8static inline size_t min(size_t a, size_t b) { return a < b ? a : b; }
9
10/// Initialize the free list. 6/// Initialize the free list.
11/// All of the blocks in the pool are assumed free. 7/// All of the blocks in the pool are assumed free.
12static void init_free_list(mempool* pool) { 8static void init_free_list(mempool* pool) {
13 assert(pool); 9 assert(pool);
14 for (size_t i = 0; i < pool->num_blocks - 1; ++i) { 10 for (size_t i = 0; i < pool->num_blocks - 1; ++i) {
15 pool->block_info[i].next = i + 1; 11 pool->block_info[i].next_free = i + 1;
16 } 12 }
17 pool->block_info[pool->num_blocks - 1].next = NO_BLOCK; 13 pool->block_info[pool->num_blocks - 1].next_free = 0;
18} 14}
19 15
20bool mempool_make_( 16bool mempool_make_(
@@ -27,6 +23,7 @@ bool mempool_make_(
27 pool->block_size_bytes = block_size_bytes; 23 pool->block_size_bytes = block_size_bytes;
28 pool->num_blocks = num_blocks; 24 pool->num_blocks = num_blocks;
29 pool->head = 0; 25 pool->head = 0;
26 pool->used = 0;
30 27
31 // Initialize blocks and block info. 28 // Initialize blocks and block info.
32 if (!block_info) { 29 if (!block_info) {
@@ -66,6 +63,7 @@ void mempool_del_(mempool* pool) {
66void mempool_clear_(mempool* pool) { 63void mempool_clear_(mempool* pool) {
67 assert(pool); 64 assert(pool);
68 pool->head = 0; 65 pool->head = 0;
66 pool->used = 0;
69 memset(pool->blocks, 0, pool->num_blocks * pool->block_size_bytes); 67 memset(pool->blocks, 0, pool->num_blocks * pool->block_size_bytes);
70 memset(pool->block_info, 0, pool->num_blocks * sizeof(BlockInfo)); 68 memset(pool->block_info, 0, pool->num_blocks * sizeof(BlockInfo));
71 init_free_list(pool); 69 init_free_list(pool);
@@ -74,15 +72,18 @@ void mempool_clear_(mempool* pool) {
74void* mempool_alloc_(mempool* pool) { 72void* mempool_alloc_(mempool* pool) {
75 assert(pool); 73 assert(pool);
76 74
77 if (pool->head == NO_BLOCK) { 75 BlockInfo* head = &pool->block_info[pool->head];
78 return 0; 76 if (head->used) {
77 return 0; // Pool is full.
79 } 78 }
80 79
81 // Allocate the block. 80 // Allocate the block.
82 BlockInfo* head = &pool->block_info[pool->head]; 81 void* block = &pool->blocks[pool->head * pool->block_size_bytes];
83 void* block = &pool->blocks[pool->head * pool->block_size_bytes]; 82 head->used = true;
84 head->used = true; 83 head->next_used = pool->used;
85 pool->head = head->next; 84 pool->used = pool->head;
85 pool->head = head->next_free;
86 head->next_free = 0;
86 87
87 return block; 88 return block;
88} 89}
@@ -104,9 +105,13 @@ void mempool_free_(mempool* pool, void** block_ptr) {
104 memset(*block_ptr, 0, pool->block_size_bytes); 105 memset(*block_ptr, 0, pool->block_size_bytes);
105 106
106 // Free the block and add it to the head of the free list. 107 // Free the block and add it to the head of the free list.
107 info->used = false; 108 info->used = false;
108 info->next = pool->head; 109 info->next_used = 0;
109 pool->head = block_index; 110 info->next_free = pool->head;
111 pool->head = block_index;
112 if (pool->used == block_index) {
113 pool->used = 0;
114 }
110 115
111 *block_ptr = 0; 116 *block_ptr = 0;
112} 117}