/**
* mpool.c
*
* Memory pool routines.
*
* Copyright 1996 by Gray Watson.
*
* This file is part of the mpool package.
*
* Permission to use, copy, modify, and distribute this software for
* any purpose and without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies, and that the name of Gray Watson not be used in advertising
* or publicity pertaining to distribution of the document or software
* without specific, written prior permission.
*
* Gray Watson makes no representations about the suitability of the
* software described herein for any purpose. It is provided "as is"
* without express or implied warranty.
*
* The author may be reached via http://256.com/gray/
*
* $Id: mpool.c,v 1.5 2006/05/31 20:28:31 gray Exp $
*
* cheungmine@gmail.com
* revised 12/7/2012
*/
/*
* Memory-pool allocation routines. I got sick of the GNU mmalloc
* library which was close to what we needed but did not exactly do
* what I wanted.
*
* The following uses mmap from /dev/zero. It allows a number of
* allocations to be made inside of a memory pool then with a clear or
* close the pool can be reset without any memory fragmentation and
* growth problems.
*/
#if defined (WIN32) || defined(WINDOWS)
#define OS_WINDOWS
#include "mix4win.h"
#else
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#ifdef DMALLOC
#include "dmalloc.h"
#endif
#endif
#define MPOOL_MAIN
#include "mpool.h"
#include "mpool_loc.h"
#ifdef __GNUC__
#ident "$Id: mpool.c,v 1.5 2006/05/31 20:28:31 gray Exp $"
#else
static char *rcs_id = "$Id: mpool.c,v 1.5 2006/05/31 20:28:31 gray Exp $";
#endif
/* version */
static char *libmp_version = "mpool library version 2.1.1r";
/* local variables */
static int libmp_initialized = 0; /* lib initialized? */
static unsigned int libmp_min_bit_free_next = 0; /* min size of next pnt */
static unsigned int libmp_min_bit_free_size = 0; /* min size of next + size */
static unsigned long libmp_bit_array[MAX_BITS + 1]; /* size -> bit */
/**
* local functions
*/
/**
* Perform any library level initialization.
*/
static void startup(void)
{
int bit_c;
unsigned long size = 1;
if (libmp_initialized) {
return;
}
/* allocate our free bit array list */
for (bit_c = 0; bit_c <= MAX_BITS; bit_c++) {
libmp_bit_array[bit_c] = size;
/*
* Note our minimum number of bits that can store a pointer. This
* is smallest address that we can have a linked list for.
*/
if (libmp_min_bit_free_next == 0 && size >= sizeof(void *)) {
libmp_min_bit_free_next = bit_c;
}
/*
* Note our minimum number of bits that can store a pointer and
* the size of the block.
*/
if (libmp_min_bit_free_size == 0 && size >= sizeof(mpool_free_t)) {
libmp_min_bit_free_size = bit_c;
}
size *= 2;
}
libmp_initialized = 1;
}
/**
* Calculate the number of bits in a size.
*/
static int size_to_bits(const unsigned long size)
{
int bit_c = 0;
for (bit_c = 0; bit_c <= MAX_BITS; bit_c++) {
if (size <= libmp_bit_array[bit_c]) {
break;
}
}
return bit_c;
}
/**
* Calculate the number of bits in a size going on the free list.
*/
static int size_to_free_bits(const unsigned long size)
{
int bit_c = 0;
if (size == 0) {
return 0;
}
for (bit_c = 0; bit_c <= MAX_BITS; bit_c++) {
if (size < libmp_bit_array[bit_c]) {
break;
}
}
return bit_c - 1;
}
/*
* Calculate the size represented by a number of bits.
*/
static unsigned long bits_to_size(const int bit_n)
{
if (bit_n > MAX_BITS) {
return libmp_bit_array[MAX_BITS];
} else {
return libmp_bit_array[bit_n];
}
}
/**
* Allocate space for a number of memory pages in the memory pool.
*/
static void *alloc_pages(mpool_t *mp_p, const unsigned int page_n, int *errcode)
{
void *mem, *fill_mem;
unsigned long size, fill;
int state;
/* are we over our max-pages? */
if (mp_p->mp_max_pages > 0 && mp_p->mp_page_c >= mp_p->mp_max_pages) {
SET_POINTER(errcode, MPOOL_E_NO_PAGES);
return NULL;
}
size = SIZE_OF_PAGES(mp_p, page_n);
#ifdef DEBUG
(void)printf("allocating %u pages or %lu bytes\n", page_n, size);
#endif
if (BIT_IS_SET(mp_p->mp_flags, MPOOL_FLAG_USE_SBRK)) {
mem = sbrk(size);
if (mem == (void *)-1) {
SET_POINTER(errcode, MPOOL_E_NO_MEMORY);
return NULL;
}
fill = (unsigned long)mem % mp_p->mp_page_size;
if (fill > 0) {
fill = mp_p->mp_page_size - fill;
fill_mem = sbrk(fill);
if (fill_mem == (void *)-1) {
SET_POINTER(errcode, MPOOL_E_NO_MEMORY);
return NULL;
}
if ((char *)fill_mem != (char *)mem + size) {
SET_POINTER(errcode, MPOOL_E_SBRK_CONTIG);
return NULL;
}
mem = (char *)mem + fill;
}
} else {
state = MAP_PRIVATE;
#ifdef MAP_FILE
state |= MAP_FILE;
#endif
#ifdef MAP_VARIABLE
state |= MAP_VARIABLE;
#endif
/* mmap from /dev/zero */
mem = mmap((caddr_t)mp_p->mp_addr, size, PROT_READ | PROT_WRITE, state, mp_p->mp_fd, mp_p->mp_top);
if (mem == (void *)MAP_FAILED) {
if (errno == ENOMEM) {
SET_POINTER(errcode, MPOOL_E_NO_MEMORY);
} else {
SET_POINTER(errcode, MPOOL_E_MMAP);
}
return NULL;
}
mp_p->mp_top += size;
if (mp_p->mp_addr != NULL) {
mp_p->mp_addr = (char *)mp_p->mp_addr + size;
}
}
mp_p->mp_page_c += page_n;
SET_POINTER(errcode, MPOOL_SUCCESS);
return mem;
}
/**
* Free previously allocated pages of memory.
*/
static int free_pages(void *pages, const unsigned long size, const int sbrk_b)
{
if (! sbrk_b) {
(void)munmap((caddr_t)pages, size);
}
return MPOOL_SUCCESS;
}
/**
* Check for the existance of the magic ID in a memory pointer.
*/
static int check_magic(const void *addr, const unsigned long size)
{
const unsigned char *mem_p;
/* set our starting point */
mem_p = (unsigned char *)addr + size;
if (*mem_p == FENCE_MAGIC0 && *(mem_p + 1) == FENCE_MAGIC1) {
return MPOOL_SUCCESS;
} else {
return MPOOL_E_POINTER_OVER;
}
}
/**
* Write the magic ID to the address.
*/
static void write_magic(const void *addr)
{
*(unsigned char *)addr = FENCE_MAGIC0;
*((unsigned char *)addr + 1) = FENCE_MAGIC1;
}
/**
* Moved a pointer into our free lists.
*/
static int free_pointer(mpool_t *mp_p, void *addr,
const unsigned long size)
{
unsigned int bit_n;
unsigned long real_size;
mpool_free_t free_pnt;
#ifdef DEBUG
(void)printf("freeing a block at %lx of %lu bytes\n", (long)addr, size);
#endif
if (size == 0) {
return MPOOL_SUCCESS;
}
/*
* if the user size is larger then can fit in an entire block then
* we change the size
*/
if (size > MAX_BLOCK_USER_MEMORYORY(mp_p)) {
real_size = SIZE_OF_PAGES(mp_p, PAGES_IN_SIZE(mp_p, size)) - sizeof(mpool_block_t);
} else {
real_size = size;
}
/*
* We use a specific free bits calculation here because if we are
* freeing 10 bytes then we will be putting it into the 8-byte free
* list and not the 16 byte list. size_to_bits(10) will return 4
* instead of 3.
*/
bit_n = size_to_free_bits(real_size);
/*
* Minimal error checking. We could go all the way through the
* list however this might be prohibitive.
*/
if (mp_p->mp_free[bit_n] == addr) {
return MPOOL_E_IS_FREE;
}
/* add the freed pointer to the free list */
if (bit_n < libmp_min_bit_free_next) {
/*
* Yes we know this will lose 99% of the allocations but what else
* can we do? No space for a next pointer.
*/
if (mp_p->mp_free[bit_n] == NULL) {
mp_p->mp_free[bit_n] = addr;
}
} else if (bit_n < libmp_m
评论10
最新资源