Files
retrobsd/tools/virtualmips/mempool.c
2014-04-09 14:27:18 +01:00

247 lines
5.1 KiB
C

/*
* Copyright (c) 1999-2006 Christophe Fillot.
* E-mail: cf@utc.fr
*
* mempool.c: Simple Memory Pools.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <ctype.h>
#include <time.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <assert.h>
#include "utils.h"
#include "mempool.h"
/*
* Internal function used to allocate a memory block, and do basic operations
* on it. It does not manipulate pools, so no mutex is needed.
*/
static inline memblock_t *memblock_alloc (size_t size, int zeroed)
{
memblock_t *block;
size_t total_size;
total_size = size + sizeof (memblock_t);
if (!(block = malloc (total_size)))
return NULL;
if (zeroed)
memset (block, 0, total_size);
block->tag = MEMBLOCK_TAG;
block->block_size = size;
block->prev = block->next = NULL;
return block;
}
/* Insert block in linked list */
static inline void memblock_insert (mempool_t * pool, memblock_t * block)
{
MEMPOOL_LOCK (pool);
pool->nr_blocks++;
pool->total_size += block->block_size;
block->prev = NULL;
block->next = pool->block_list;
if (block->next)
block->next->prev = block;
pool->block_list = block;
MEMPOOL_UNLOCK (pool);
}
/* Remove block from linked list */
static inline void memblock_delete (mempool_t * pool, memblock_t * block)
{
MEMPOOL_LOCK (pool);
pool->nr_blocks--;
pool->total_size -= block->block_size;
if (!block->prev)
pool->block_list = block->next;
else
block->prev->next = block->next;
if (block->next)
block->next->prev = block->prev;
block->next = block->prev = NULL;
MEMPOOL_UNLOCK (pool);
}
/* Allocate a new block in specified pool (internal function) */
static inline void *mp_alloc_inline (mempool_t * pool, size_t size,
int zeroed)
{
memblock_t *block;
if (!(block = memblock_alloc (size, zeroed)))
return NULL;
block->pool = pool;
memblock_insert (pool, block);
return (block->data);
}
/* Allocate a new block in specified pool */
void *mp_alloc (mempool_t * pool, size_t size)
{
return (mp_alloc_inline (pool, size, TRUE));
}
/* Allocate a new block which will not be zeroed */
void *mp_alloc_n0 (mempool_t * pool, size_t size)
{
return (mp_alloc_inline (pool, size, FALSE));
}
/* Reallocate a block */
void *mp_realloc (void *addr, size_t new_size)
{
memblock_t *ptr, *block = (memblock_t *) addr - 1;
mempool_t *pool;
size_t total_size;
assert (block->tag == MEMBLOCK_TAG);
pool = block->pool;
/* remove this block from list */
memblock_delete (pool, block);
/* reallocate block with specified size */
total_size = new_size + sizeof (memblock_t);
if (!(ptr = realloc (block, total_size))) {
memblock_insert (pool, block);
return NULL;
}
ptr->block_size = new_size;
memblock_insert (pool, ptr);
return ptr->data;
}
/* Allocate a new memory block and copy data into it */
void *mp_dup (mempool_t * pool, void *data, size_t size)
{
void *p;
if ((p = mp_alloc_n0 (pool, size)))
memcpy (p, data, size);
return p;
}
/* Duplicate specified string and insert it in a memory pool */
char *mp_strdup (mempool_t * pool, char *str)
{
char *new_str;
if ((new_str = mp_alloc (pool, strlen (str) + 1)) == NULL)
return NULL;
strcpy (new_str, str);
return new_str;
}
/* Free block at specified address */
int mp_free (void *addr)
{
memblock_t *block = (memblock_t *) addr - 1;
mempool_t *pool;
if (addr != NULL) {
assert (block->tag == MEMBLOCK_TAG);
pool = block->pool;
memblock_delete (pool, block);
memset (block, 0, sizeof (memblock_t));
free (block);
}
return (0);
}
/* Free block at specified address and clean pointer */
int mp_free_ptr (void *addr)
{
void *p;
assert (addr != NULL);
p = *(void **) addr;
*(void **) addr = NULL;
mp_free (p);
return (0);
}
/* Free all blocks of specified pool */
void mp_free_all_blocks (mempool_t * pool)
{
memblock_t *block, *next;
MEMPOOL_LOCK (pool);
for (block = pool->block_list; block; block = next) {
next = block->next;
free (block);
}
pool->block_list = NULL;
pool->nr_blocks = 0;
pool->total_size = 0;
MEMPOOL_UNLOCK (pool);
}
/* Free specified memory pool */
void mp_free_pool (mempool_t * pool)
{
mp_free_all_blocks (pool);
if (!(pool->flags & MEMPOOL_FIXED))
free (pool);
}
/* Create a new pool in a fixed memory area */
mempool_t *mp_create_fixed_pool (mempool_t * mp, char *name)
{
memset (mp, 0, sizeof (*mp));
if (pthread_mutex_init (&mp->lock, NULL) != 0)
return NULL;
mp->name = name;
mp->block_list = NULL;
mp->flags = MEMPOOL_FIXED;
return mp;
}
/* Create a new pool */
mempool_t *mp_create_pool (char *name)
{
mempool_t *mp = malloc (sizeof (*mp));
if (!mp || !mp_create_fixed_pool (mp, name)) {
free (mp);
return NULL;
}
mp->flags = 0; /* clear "FIXED" flag */
return mp;
}