You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

198 lines
5.4 KiB

/* -*- coding: utf-8 -*-
* ----------------------------------------------------------------------
* Copyright © 2012-2015, RedJack, LLC.
* All rights reserved.
*
* Please see the COPYING file in this distribution for license details.
* ----------------------------------------------------------------------
*/
#include <assert.h>
#include <stdlib.h>
#include "libcork/core/callbacks.h"
#include "libcork/core/mempool.h"
#include "libcork/core/types.h"
#include "libcork/helpers/errors.h"
#if !defined(CORK_DEBUG_MEMPOOL)
#define CORK_DEBUG_MEMPOOL 0
#endif
#if CORK_DEBUG_MEMPOOL
#include <stdio.h>
#define DEBUG(...) fprintf(stderr, __VA_ARGS__)
#else
#define DEBUG(...) /* no debug messages */
#endif
struct cork_mempool {
size_t element_size;
size_t block_size;
struct cork_mempool_object *free_list;
/* The number of objects that have been given out by
* cork_mempool_new but not returned via cork_mempool_free. */
size_t allocated_count;
struct cork_mempool_block *blocks;
void *user_data;
cork_free_f free_user_data;
cork_init_f init_object;
cork_done_f done_object;
};
struct cork_mempool_object {
/* When this object is unclaimed, it will be in the cork_mempool
* object's free_list using this pointer. */
struct cork_mempool_object *next_free;
};
struct cork_mempool_block {
struct cork_mempool_block *next_block;
};
#define cork_mempool_object_size(mp) \
(sizeof(struct cork_mempool_object) + (mp)->element_size)
#define cork_mempool_get_header(obj) \
(((struct cork_mempool_object *) (obj)) - 1)
#define cork_mempool_get_object(hdr) \
((void *) (((struct cork_mempool_object *) (hdr)) + 1))
struct cork_mempool *
cork_mempool_new_size_ex(size_t element_size, size_t block_size)
{
struct cork_mempool *mp = cork_new(struct cork_mempool);
mp->element_size = element_size;
mp->block_size = block_size;
mp->free_list = NULL;
mp->allocated_count = 0;
mp->blocks = NULL;
mp->user_data = NULL;
mp->free_user_data = NULL;
mp->init_object = NULL;
mp->done_object = NULL;
return mp;
}
void
cork_mempool_free(struct cork_mempool *mp)
{
struct cork_mempool_block *curr;
assert(mp->allocated_count == 0);
if (mp->done_object != NULL) {
struct cork_mempool_object *obj;
for (obj = mp->free_list; obj != NULL; obj = obj->next_free) {
mp->done_object
(mp->user_data, cork_mempool_get_object(obj));
}
}
for (curr = mp->blocks; curr != NULL; ) {
struct cork_mempool_block *next = curr->next_block;
cork_free(curr, mp->block_size);
/* Do this here instead of in the for statement to avoid
* accessing the just-freed block. */
curr = next;
}
cork_free_user_data(mp);
cork_delete(struct cork_mempool, mp);
}
void
cork_mempool_set_user_data(struct cork_mempool *mp,
void *user_data, cork_free_f free_user_data)
{
cork_free_user_data(mp);
mp->user_data = user_data;
mp->free_user_data = free_user_data;
}
void
cork_mempool_set_init_object(struct cork_mempool *mp, cork_init_f init_object)
{
mp->init_object = init_object;
}
void
cork_mempool_set_done_object(struct cork_mempool *mp, cork_done_f done_object)
{
mp->done_object = done_object;
}
void
cork_mempool_set_callbacks(struct cork_mempool *mp,
void *user_data, cork_free_f free_user_data,
cork_init_f init_object,
cork_done_f done_object)
{
cork_mempool_set_user_data(mp, user_data, free_user_data);
cork_mempool_set_init_object(mp, init_object);
cork_mempool_set_done_object(mp, done_object);
}
/* If this function succeeds, then we guarantee that there will be at
* least one object in mp->free_list. */
static void
cork_mempool_new_block(struct cork_mempool *mp)
{
/* Allocate the new block and add it to mp's block list. */
struct cork_mempool_block *block;
void *vblock;
DEBUG("Allocating new %zu-byte block\n", mp->block_size);
block = cork_malloc(mp->block_size);
block->next_block = mp->blocks;
mp->blocks = block;
vblock = block;
/* Divide the block's memory region into a bunch of objects. */
size_t index = sizeof(struct cork_mempool_block);
for (index = sizeof(struct cork_mempool_block);
(index + cork_mempool_object_size(mp)) <= mp->block_size;
index += cork_mempool_object_size(mp)) {
struct cork_mempool_object *obj = vblock + index;
DEBUG(" New object at %p[%p]\n", cork_mempool_get_object(obj), obj);
if (mp->init_object != NULL) {
mp->init_object
(mp->user_data, cork_mempool_get_object(obj));
}
obj->next_free = mp->free_list;
mp->free_list = obj;
}
}
void *
cork_mempool_new_object(struct cork_mempool *mp)
{
struct cork_mempool_object *obj;
void *ptr;
if (CORK_UNLIKELY(mp->free_list == NULL)) {
cork_mempool_new_block(mp);
}
obj = mp->free_list;
mp->free_list = obj->next_free;
mp->allocated_count++;
ptr = cork_mempool_get_object(obj);
return ptr;
}
void
cork_mempool_free_object(struct cork_mempool *mp, void *ptr)
{
struct cork_mempool_object *obj = cork_mempool_get_header(ptr);
DEBUG("Returning %p[%p] to memory pool\n", ptr, obj);
obj->next_free = mp->free_list;
mp->free_list = obj;
mp->allocated_count--;
}