2000-12-16 12:38:21 +00:00
|
|
|
/*
|
2010-02-24 16:01:14 +00:00
|
|
|
* Copyright (c) 1995-2010 Peter Simons <simons@cryp.to>
|
|
|
|
|
* Copyright (c) 2000-2001 Cable & Wireless GmbH
|
|
|
|
|
* Copyright (c) 1999-2000 CyberSolutions GmbH
|
|
|
|
|
*
|
|
|
|
|
* This program is free software: you can redistribute it and/or modify it under
|
|
|
|
|
* the terms of the GNU General Public License as published by the Free Software
|
|
|
|
|
* Foundation, either version 3 of the License, or (at your option) any later
|
|
|
|
|
* version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
|
|
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
|
|
|
* details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License along with
|
|
|
|
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
2000-12-16 12:38:21 +00:00
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
#include "../liblists/lists.h"
|
|
|
|
|
#include "mpools.h"
|
|
|
|
|
|
|
|
|
|
static List mpools_list = NULL;
|
|
|
|
|
|
|
|
|
|
/********** Internal routines **********/
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
GetMemoryPool(const char * pool_name,
|
2010-02-24 16:24:28 +00:00
|
|
|
Node * node_ptr,
|
|
|
|
|
struct mp_list_entry ** mpool_entry_ptr)
|
2000-12-16 12:38:21 +00:00
|
|
|
{
|
|
|
|
|
Node node;
|
|
|
|
|
|
|
|
|
|
/* Sanity checks. */
|
|
|
|
|
|
|
|
|
|
assert(mpools_list != NULL);
|
|
|
|
|
assert(pool_name != NULL);
|
|
|
|
|
if (pool_name == NULL)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
/* Find the pool of the right name. */
|
|
|
|
|
|
|
|
|
|
node = FindNodeByKey(mpools_list, (const void *) pool_name);
|
|
|
|
|
if (node != NULL) {
|
2010-02-24 16:24:28 +00:00
|
|
|
if (node_ptr != NULL)
|
|
|
|
|
*node_ptr = node;
|
|
|
|
|
if (mpool_entry_ptr != NULL)
|
|
|
|
|
*mpool_entry_ptr = (struct mp_list_entry *) getNodeData(node);
|
|
|
|
|
return 0;
|
2000-12-16 12:38:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* No entry available. So we create one. */
|
|
|
|
|
|
|
|
|
|
pool_name = strdup(pool_name);
|
|
|
|
|
if (pool_name == NULL)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
node = AppendNode(mpools_list, (const void *) pool_name, NULL);
|
|
|
|
|
if (node == NULL) {
|
2010-02-24 16:24:28 +00:00
|
|
|
free(pool_name);
|
|
|
|
|
return -1;
|
2000-12-16 12:38:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Return result to caller. */
|
|
|
|
|
|
|
|
|
|
if (node_ptr != NULL)
|
|
|
|
|
*node_ptr = node;
|
|
|
|
|
if (mpool_entry_ptr != NULL)
|
|
|
|
|
*mpool_entry_ptr = (struct mp_list_entry *) getNodeData(node);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/********** User interface **********/
|
|
|
|
|
|
|
|
|
|
/* mp_malloc() allocates a block of memory using malloc(3), adds the
|
|
|
|
|
pointer and the size of the block to the memory pool as identified
|
|
|
|
|
by the 'pool_name' argument and returns the address of the memory
|
|
|
|
|
block to the caller.
|
|
|
|
|
|
|
|
|
|
Memory pools are identified by a byte string, terminated with a
|
|
|
|
|
zero ('\\0') byte. The names are compared using strcmp(3), which is
|
|
|
|
|
case-sensitive.
|
|
|
|
|
|
|
|
|
|
RETURNS: If successfull, mp_malloc() returns a pointer to the newly
|
|
|
|
|
allocated memory block. In case of failure, NULL is returned
|
|
|
|
|
instead.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void *
|
|
|
|
|
mp_malloc(const char * pool_name /* ID-String of the memory pool. */,
|
2010-02-24 16:24:28 +00:00
|
|
|
size_t block_size /* Size of the requested memory block. */
|
|
|
|
|
)
|
2000-12-16 12:38:21 +00:00
|
|
|
{
|
|
|
|
|
struct mp_list_entry * mpool;
|
|
|
|
|
Node node;
|
|
|
|
|
void * block;
|
|
|
|
|
|
|
|
|
|
/* Sanity checks. */
|
|
|
|
|
|
|
|
|
|
assert(pool_name != NULL);
|
|
|
|
|
if (pool_name == NULL || block_size <= 0)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
/* Init the internal list structure, if it isn't already. */
|
|
|
|
|
|
|
|
|
|
if (mpools_list == NULL) {
|
2010-02-24 16:24:28 +00:00
|
|
|
mpools_list = InitList((int (*)(const void *, const void *)) strcmp);
|
|
|
|
|
if (mpools_list == NULL)
|
|
|
|
|
return NULL;
|
2000-12-16 12:38:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Get the pool structure. */
|
|
|
|
|
|
|
|
|
|
if (GetMemoryPool(pool_name, &node, NULL) != 0)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
/* Allocate the memory. */
|
|
|
|
|
|
|
|
|
|
mpool = malloc(sizeof(struct mp_list_entry));
|
|
|
|
|
if (mpool == NULL)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
block = malloc(block_size);
|
|
|
|
|
if (block == NULL) {
|
2010-02-24 16:24:28 +00:00
|
|
|
free(mpool);
|
|
|
|
|
return NULL;
|
2000-12-16 12:38:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Init the mpool structure. */
|
|
|
|
|
|
|
|
|
|
mpool->next = NULL;
|
|
|
|
|
mpool->block = block;
|
|
|
|
|
mpool->size = block_size;
|
|
|
|
|
|
|
|
|
|
/* Now append the structure to our list. */
|
|
|
|
|
|
|
|
|
|
if (getNodeData(node) != NULL)
|
|
|
|
|
mpool->next = (struct mp_list_entry *) getNodeData(node);
|
|
|
|
|
setNodeData(node, (const void *) mpool);
|
|
|
|
|
|
|
|
|
|
return block;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* mp_free() will return the previously allocated memory block to the
|
|
|
|
|
system and remove the entry from the memory pool. The memory block
|
|
|
|
|
has to be previously allocated by mp_malloc(), or mp_free() won't
|
|
|
|
|
do anything.
|
|
|
|
|
|
|
|
|
|
It is safe to call mp_free() several times for the same memory
|
|
|
|
|
block, or for an invalid memory block, that hasn't been allocated
|
|
|
|
|
by mp_malloc(). mp_free will detect this and return without doing
|
|
|
|
|
anything.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
mp_free(const char * pool_name /* ID-String of the memory pool. */,
|
2010-02-24 16:24:28 +00:00
|
|
|
void * block /* Pointer to a memory block
|
|
|
|
|
previously allocated by mp_malloc(). */
|
|
|
|
|
)
|
2000-12-16 12:38:21 +00:00
|
|
|
{
|
|
|
|
|
struct mp_list_entry * mpool,
|
|
|
|
|
* prev_mpool;
|
|
|
|
|
Node node;
|
|
|
|
|
|
|
|
|
|
/* Sanity checks. */
|
|
|
|
|
|
|
|
|
|
assert(pool_name != NULL);
|
|
|
|
|
if (pool_name == NULL)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* Init the internal list structure, if it isn't already. */
|
|
|
|
|
|
|
|
|
|
if (mpools_list == NULL) {
|
2010-02-24 16:24:28 +00:00
|
|
|
mpools_list = InitList(NULL);
|
|
|
|
|
if (mpools_list == NULL)
|
|
|
|
|
return;
|
2000-12-16 12:38:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Get the pool structure. */
|
|
|
|
|
|
|
|
|
|
if (GetMemoryPool(pool_name, &node, &mpool) != 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* Find the block we should free. */
|
|
|
|
|
|
|
|
|
|
for (prev_mpool = NULL;
|
2010-02-24 16:24:28 +00:00
|
|
|
mpool != NULL && mpool->block != block;
|
|
|
|
|
prev_mpool = mpool, mpool = mpool->next)
|
2000-12-16 12:38:21 +00:00
|
|
|
;
|
|
|
|
|
|
2010-02-24 16:24:28 +00:00
|
|
|
if (mpool == NULL) { /* block not found */
|
|
|
|
|
printf("Warning\n");
|
|
|
|
|
return;
|
2000-12-16 12:38:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Remove the node from the linked list. */
|
|
|
|
|
|
|
|
|
|
if (prev_mpool == NULL)
|
|
|
|
|
setNodeData(node, mpool->next);
|
|
|
|
|
else
|
|
|
|
|
prev_mpool->next = mpool->next;
|
|
|
|
|
|
|
|
|
|
/* And free it plus our own structure stuff. */
|
|
|
|
|
|
|
|
|
|
free(mpool->block);
|
|
|
|
|
free(mpool);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Remove the provided memory block from the memory pool, without
|
|
|
|
|
freeing the memory itself.
|
|
|
|
|
|
|
|
|
|
It is safe to call mp_remove_block_from_pool() with invalid data.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
mp_remove_block_from_pool(const char * pool_name /* ID-String of the memory pool. */,
|
2010-02-24 16:24:28 +00:00
|
|
|
void * block /* Pointer to a memory block
|
|
|
|
|
previously allocated by mp_malloc(). */
|
|
|
|
|
)
|
2000-12-16 12:38:21 +00:00
|
|
|
{
|
|
|
|
|
struct mp_list_entry * mpool,
|
|
|
|
|
* prev_mpool;
|
|
|
|
|
Node node;
|
|
|
|
|
|
|
|
|
|
/* Sanity checks. */
|
|
|
|
|
|
|
|
|
|
assert(pool_name != NULL);
|
|
|
|
|
assert(block != NULL);
|
|
|
|
|
if (!pool_name || !block)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* Init the internal list structure, if it isn't already. */
|
|
|
|
|
|
|
|
|
|
if (mpools_list == NULL) {
|
2010-02-24 16:24:28 +00:00
|
|
|
mpools_list = InitList(NULL);
|
|
|
|
|
return;
|
2000-12-16 12:38:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Get the pool structure. */
|
|
|
|
|
|
|
|
|
|
if (GetMemoryPool(pool_name, &node, &mpool) != 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* Find the block we should free. */
|
|
|
|
|
|
|
|
|
|
for (prev_mpool = NULL;
|
2010-02-24 16:24:28 +00:00
|
|
|
mpool != NULL && mpool->block != block;
|
|
|
|
|
prev_mpool = mpool, mpool = mpool->next)
|
2000-12-16 12:38:21 +00:00
|
|
|
;
|
|
|
|
|
|
2010-02-24 16:24:28 +00:00
|
|
|
if (mpool == NULL) /* block not found */
|
2000-12-16 12:38:21 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* Remove the node from the linked list. */
|
|
|
|
|
|
|
|
|
|
if (prev_mpool == NULL)
|
|
|
|
|
setNodeData(node, mpool->next);
|
|
|
|
|
else
|
|
|
|
|
prev_mpool->next = mpool->next;
|
|
|
|
|
|
|
|
|
|
/* Free the structure stuff. */
|
|
|
|
|
|
|
|
|
|
free(mpool);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This routine will return all allocated memory blocks contained in
|
|
|
|
|
pool 'pool_name' to the system.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
mp_free_memory_pool(const char * pool_name /* ID-String of the memory pool. */
|
2010-02-24 16:24:28 +00:00
|
|
|
)
|
2000-12-16 12:38:21 +00:00
|
|
|
{
|
|
|
|
|
struct mp_list_entry * mpool_entry,
|
2010-02-24 16:24:28 +00:00
|
|
|
* next_mpool_entry;
|
2000-12-16 12:38:21 +00:00
|
|
|
Node node;
|
|
|
|
|
|
|
|
|
|
/* Sanity checks. */
|
|
|
|
|
|
|
|
|
|
assert(pool_name != NULL);
|
|
|
|
|
if (pool_name == NULL)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (mpools_list == NULL)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* Find our memory pool. */
|
|
|
|
|
|
|
|
|
|
node = FindNodeByKey(mpools_list, pool_name);
|
|
|
|
|
if (node == NULL)
|
|
|
|
|
return;
|
|
|
|
|
mpool_entry = (struct mp_list_entry *) getNodeData(node);
|
|
|
|
|
|
|
|
|
|
/* And now we move the pool completely. */
|
|
|
|
|
|
|
|
|
|
RemoveNode(node);
|
2010-02-24 16:07:37 +00:00
|
|
|
free(getNodeKey(node)); /* kill the pool name buffer */
|
2000-12-16 12:38:21 +00:00
|
|
|
FreeNode(node);
|
|
|
|
|
|
|
|
|
|
for ( ; mpool_entry != NULL; mpool_entry = next_mpool_entry) {
|
2010-02-24 16:24:28 +00:00
|
|
|
next_mpool_entry = mpool_entry->next;
|
|
|
|
|
free(mpool_entry->block);
|
|
|
|
|
free(mpool_entry);
|
2000-12-16 12:38:21 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* This routine is experimental and for debugging purposes only. In
|
|
|
|
|
the current version, it will dump the contents of pool 'pool_name'
|
|
|
|
|
to the screen, using printf(3).
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
mp_dump_memory_pool(const char * pool_name /* ID-String of the memory pool. */
|
2010-02-24 16:24:28 +00:00
|
|
|
)
|
2000-12-16 12:38:21 +00:00
|
|
|
{
|
|
|
|
|
struct mp_list_entry * mpool_entry;
|
|
|
|
|
unsigned int total;
|
|
|
|
|
|
|
|
|
|
/* Sanity checks. */
|
|
|
|
|
|
|
|
|
|
assert(pool_name != NULL);
|
|
|
|
|
if (pool_name == NULL)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* Dump the specified pool. */
|
|
|
|
|
|
|
|
|
|
if (GetMemoryPool(pool_name, NULL, &mpool_entry) != 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (mpool_entry == NULL) {
|
2010-02-24 16:24:28 +00:00
|
|
|
printf("mpool \"%s\" is empty.\n", pool_name);
|
|
|
|
|
return;
|
2000-12-16 12:38:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (total = 0; mpool_entry != NULL; mpool_entry = mpool_entry->next) {
|
2010-02-24 16:24:28 +00:00
|
|
|
printf("\"%s\": %d byte block at $%08x.\n", pool_name, mpool_entry->size,
|
|
|
|
|
(unsigned int) mpool_entry->block);
|
|
|
|
|
total += mpool_entry->size;
|
2000-12-16 12:38:21 +00:00
|
|
|
}
|
|
|
|
|
printf("Total size of mpool \"%s\" is %u byte.\n", pool_name, total);
|
|
|
|
|
}
|