7 mpret_t
mpool_init(mpool_t
**mpool
, size_t maxlogsize
, size_t minlogsize
)
13 if (maxlogsize
< minlogsize
)
16 /* Allocate memory for memory pool data structure */
17 if ((*mpool
= malloc(sizeof **mpool
)) == NULL
)
20 (*mpool
)->maxlogsize
= maxlogsize
;
21 (*mpool
)->minlogsize
= minlogsize
;
22 (*mpool
)->nblocks
= (*mpool
)->maxlogsize
- (*mpool
)->minlogsize
+ 1;
24 (*mpool
)->nsplits
= 0;
25 (*mpool
)->nmerges
= 0;
28 /* Allocate the actual memory of the pool */
29 DPRINTF(("Allocating %u bytes for pool\n", 1 << maxlogsize
));
30 DPRINTF(("maxlogsize = %u\tminlogsize = %u\tnblocks = %u\n",
34 if (((*mpool
)->mem
= malloc(1 << maxlogsize
)) == NULL
) {
39 /* Allocate memory for block lists */
40 if (((*mpool
)->blktable
= malloc((*mpool
)->nblocks
* sizeof *(*mpool
)->blktable
)) == NULL
) {
46 /* Initialize block lists */
47 for (i
= 0; i
< (*mpool
)->nblocks
; i
++)
48 LIST_INIT(&(*mpool
)->blktable
[i
]);
51 * Initially, before any storage has been requested,
52 * we have a single available block of length 2^maxlogsize
55 if ((pblknode
= malloc(sizeof *pblknode
)) == NULL
) {
56 free((*mpool
)->blktable
);
61 pblknode
->ptr
= (*mpool
)->mem
;
62 pblknode
->flags
|= NODE_AVAIL
; /* Mark as available */
63 pblknode
->logsize
= maxlogsize
;
65 LIST_INSERT_HEAD(&(*mpool
)->blktable
[0], pblknode
, next_block
);
67 mpool_printblks(*mpool
);
72 void *mpool_alloc(mpool_t
*mpool
, size_t size
)
76 blknode_t
*pavailnode
;
78 unsigned int i
, newpos
;
80 DPRINTF(("\n\n=======================================================\n\n"));
81 DPRINTF(("Searching for block of bytes: %u\n", size
));
84 * Find the most suitable 2^j bytes block for the requested size of bytes.
85 * The condition 2^j >= size must be satisfied for the smallest possible value
86 * of j and the block must be marked as available ofcourse.
89 for (i
= 0; i
< mpool
->nblocks
; i
++) {
90 DPRINTF(("Searcing block: %u\n", i
));
91 phead
= &mpool
->blktable
[i
];
92 if ((pnode
= LIST_FIRST(phead
)) != NULL
) {
93 if ((unsigned)(1 << pnode
->logsize
) >= size
) {
94 LIST_FOREACH(pnode
, phead
, next_block
) {
95 if (pnode
->flags
& NODE_AVAIL
) {
105 /* Failure, no available block */
106 if (pavailnode
== NULL
) {
107 DPRINTF(("No available block found\n"));
110 DPRINTF(("Found block of bytes %u\n", 1 << pavailnode
->logsize
));
112 /* Is a split required ? */
114 DPRINTF(("size = %u\tp = %u\tp-1 = %u\n",
116 1 << pavailnode
->logsize
,
117 1 << (pavailnode
->logsize
- 1)));
120 * We don't need to split the chunk we just found,
121 * if one the following statements is true:
123 * - `size' bytes fit exactly in the chunk
124 * - `size' bytes won't fit in the divided chunk
125 * - `minlogsize' constraint will be violated if we split
127 * NOTE: log2(size/2) = log2(size) - log2(2) = log2(size) - 1
129 if ((size
== (unsigned)(1 << pavailnode
->logsize
))
130 || (size
> (unsigned)(1 << (pavailnode
->logsize
- 1)))
131 || (mpool
->minlogsize
> (pavailnode
->logsize
- 1))) {
132 DPRINTF(("No split required\n"));
133 pavailnode
->flags
&= ~NODE_AVAIL
; /* Mark as no longer available */
134 mpool_printblks(mpool
);
135 return pavailnode
->ptr
;
138 DPRINTF(("Splitting...\n"));
140 mpool
->nsplits
++; /* FIXME: print a message if it overflows */
143 /* Remove old block */
144 DPRINTF(("Removing old chunk from list\n"));
145 LIST_REMOVE(pavailnode
, next_block
);
146 mpool_printblks(mpool
);
147 pavailnode
->logsize
--;
148 pavailnode
->flags
&= ~NODE_LR
; /* Mark as left buddy */
150 DPRINTF(("New size is now: %u bytes\n", 1 << pavailnode
->logsize
));
151 DPRINTF(("Moving old chunk to new position\n"));
152 newpos
= mpool
->nblocks
- pavailnode
->logsize
;
153 LIST_INSERT_HEAD(&mpool
->blktable
[newpos
], pavailnode
, next_block
);
154 mpool_printblks(mpool
);
157 DPRINTF(("Will add new item with bytes: %u\n", 1 << pavailnode
->logsize
));
158 if ((pnewnode
= malloc(sizeof *pnewnode
)) == NULL
)
160 pnewnode
->ptr
= (char *)pavailnode
->ptr
+ (1 << pavailnode
->logsize
);
161 pnewnode
->flags
|= NODE_AVAIL
; /* Mark as available */
162 pnewnode
->flags
|= NODE_LR
; /* Mark as right buddy */
163 pnewnode
->logsize
= pavailnode
->logsize
;
164 LIST_INSERT_HEAD(&mpool
->blktable
[newpos
], pnewnode
, next_block
);
165 mpool_printblks(mpool
);
171 void mpool_free(mpool_t
*mpool
, void *ptr
)
174 blknode_t
*pnode
, *pbuddy
;
175 unsigned int i
, newpos
;
178 DPRINTF(("Freeing ptr: %p\n", ptr
));
180 /* Search all nodes to find the one that points to ptr */
181 for (i
= 0; i
< mpool
->nblocks
; i
++) {
182 DPRINTF(("Searching for ptr %p in block: %u\n", ptr
, i
));
183 phead
= &mpool
->blktable
[i
];
184 LIST_FOREACH(pnode
, phead
, next_block
) {
185 if (pnode
->ptr
== ptr
) {
186 DPRINTF(("Found chunk at block: %u\tBlock has chunks with bytes: %u\n",
187 i
, 1 << pnode
->logsize
));
194 if (pnode
->logsize
== mpool
->maxlogsize
) {
195 pnode
->flags
|= NODE_AVAIL
;
199 /* Calculate possible buddy of chunk */
200 if (pnode
->flags
& NODE_LR
)
201 buddyptr
= (char *)pnode
->ptr
- (1 << pnode
->logsize
);
203 buddyptr
= (char *)pnode
->ptr
+ (1 << pnode
->logsize
);
206 * Search buddy node with address `buddyptr'.
207 * If there is indeed a buddy of `pnode', it will be in
208 * the same linked list with the latter.
210 * NOTE: nodes that belong to the same linked list,
211 * point to memory chunks with the same size.
213 DPRINTF(("Chunk: %p\tPossible buddy at: %p\n", pnode
->ptr
, buddyptr
));
214 DPRINTF(("Searching for buddy with address: %p\n", buddyptr
));
216 LIST_FOREACH(pbuddy
, phead
, next_block
) {
217 if (pbuddy
->ptr
== buddyptr
) {
218 DPRINTF(("Buddy found\n"));
223 /* If there is no buddy of `pnode', just free it and we are done */
224 if (pbuddy
== NULL
) {
225 DPRINTF(("Not found\n"));
226 DPRINTF(("Freeing it (marking it as available)\n"));
227 pnode
->flags
|= NODE_AVAIL
;
228 mpool_printblks(mpool
);
231 /* There is a buddy, attempt to coalesce if possible */
233 DPRINTF(("Trying to coalesce buddies\n"));
234 DPRINTF(("Is buddy free also ? %s\n", pbuddy
->flags
& NODE_AVAIL
? "Yes" : "No"));
235 if (pbuddy
->flags
& NODE_AVAIL
) {
236 DPRINTF(("Removing chunk from old position\n"));
237 LIST_REMOVE(pnode
, next_block
);
238 mpool_printblks(mpool
);
240 pnode
->flags
|= NODE_AVAIL
; /* Mark as available */
241 newpos
= mpool
->nblocks
- pnode
->logsize
;
242 phead
= &mpool
->blktable
[newpos
];
244 DPRINTF(("Inserting chunk to new position\n"));
245 LIST_INSERT_HEAD(phead
, pnode
, next_block
);
246 mpool_printblks(mpool
);
248 DPRINTF(("Removing buddy\n"));
249 LIST_REMOVE(pbuddy
, next_block
);
251 mpool_printblks(mpool
);
257 void mpool_destroy(mpool_t
*mpool
)
259 const blkhead_t
*phead
;
263 /* Free all nodes in all block lists */
264 for (i
= 0; i
< mpool
->nblocks
; i
++) {
265 phead
= &mpool
->blktable
[i
];
266 while ((pnode
= LIST_FIRST(phead
)) != NULL
) {
267 LIST_REMOVE(pnode
, next_block
);
272 free(mpool
->blktable
);
277 void mpool_printblks(const mpool_t
*mpool
)
279 const blkhead_t
*phead
;
280 const blknode_t
*pnode
;
283 for (i
= 0; i
< mpool
->nblocks
; i
++) {
284 DPRINTF(("Block: %u\t", i
));
286 phead
= &mpool
->blktable
[i
];
287 LIST_FOREACH(pnode
, phead
, next_block
) {
288 DPRINTF(("chunk(addr = %p, bytes = %u, av = %d, lr = %d)\t",
290 (unsigned) (1 << pnode
->logsize
),
291 pnode
->flags
& NODE_AVAIL
? 1 : 0,
292 pnode
->flags
& NODE_LR
? 1 : 0));
299 void mpool_stat_get_nodes(const mpool_t
*mpool
, size_t *avail
, size_t *used
)
301 const blkhead_t
*phead
;
302 const blknode_t
*pnode
;
307 for (i
= 0; i
< mpool
->nblocks
; i
++) {
308 phead
= &mpool
->blktable
[i
];
309 LIST_FOREACH(pnode
, phead
, next_block
) {
310 if (pnode
->flags
& NODE_AVAIL
)
318 void mpool_stat_get_bytes(const mpool_t
*mpool
, size_t *avail
, size_t *used
)
320 const blkhead_t
*phead
;
321 const blknode_t
*pnode
;
324 for (i
= 0; i
< mpool
->nblocks
; i
++) {
325 phead
= &mpool
->blktable
[i
];
326 LIST_FOREACH(pnode
, phead
, next_block
) {
327 if (pnode
->flags
& NODE_AVAIL
)
328 *avail
+= 1 << pnode
->logsize
;
330 *used
+= 1 << pnode
->logsize
;
336 size_t mpool_stat_get_splits(const mpool_t
*mpool
)
338 return mpool
->nsplits
;
341 size_t mpool_stat_get_merges(const mpool_t
*mpool
)
343 return mpool
->nmerges
;
351 size_t an
= 1, un
= 0, ab
= 1, ub
= 0;
354 if (mpool_init(&mpool
, 10, 1) == MP_ENOMEM
) {
355 fprintf(stderr
, "Not enough memory\n");
359 for (i
= 0; i
< 10; i
++) {
360 if ((p
[i
] = mpool_alloc(mpool
, S
= (1 << ((rand() % 10))))) == NULL
)
365 mpool_free(mpool
, p
[i
]);
369 mpool_stat_get_nodes(mpool
, &an
, &un
);
370 mpool_stat_get_bytes(mpool
, &ab
, &ub
);
371 DPRINTF(("avail nodes = %u\tused nodes = %u\tfree(%%) = %f\n", an
, un
, 100.0 * an
/ (an
+ un
)));
372 DPRINTF(("avail bytes = %u\tused bytes = %u\tfree(%%) = %f\n", ab
, ub
, 100.0 * ab
/ (ab
+ ub
)));
374 mpool_destroy(mpool
);