Made mempool.c threadsafe (#234)
This commit is contained in:
240
src/mempool.c
240
src/mempool.c
@@ -1,17 +1,9 @@
|
|||||||
/* mempool.c
|
/* mempool.c
|
||||||
**
|
**
|
||||||
** A simple fast memory allocation package.
|
** A simple fast pooled memory allocation package.
|
||||||
**
|
**
|
||||||
** By Steve Hill in Graphics Gems III, David Kirk (ed.),
|
** Based on code by Steve Hill in Graphics Gems III,
|
||||||
** Academic Press, Boston, MA, 1992
|
** David Kirk (ed.), Academic Press, Boston, MA, 1992
|
||||||
**
|
|
||||||
** Modified by Lew Rossman, 8/13/94.
|
|
||||||
**
|
|
||||||
** AllocInit() - create an alloc pool, returns the old pool handle
|
|
||||||
** Alloc() - allocate memory
|
|
||||||
** AllocReset() - reset the current pool
|
|
||||||
** AllocSetPool() - set the current pool
|
|
||||||
** AllocFree() - free the memory used by the current pool.
|
|
||||||
**
|
**
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -28,95 +20,80 @@
|
|||||||
|
|
||||||
#define ALLOC_BLOCK_SIZE 64000 /*(62*1024)*/
|
#define ALLOC_BLOCK_SIZE 64000 /*(62*1024)*/
|
||||||
|
|
||||||
/*
|
struct MemBlock
|
||||||
** alloc_hdr_t - Header for each block of memory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef struct alloc_hdr_s
|
|
||||||
{
|
{
|
||||||
struct alloc_hdr_s *next; /* Next Block */
|
struct MemBlock *next; // Next block
|
||||||
char *block, /* Start of block */
|
char *block, // Start of block
|
||||||
*free, /* Next free in block */
|
*free, // Next free position in block
|
||||||
*end; /* block + block size */
|
*end; // block + block size
|
||||||
} alloc_hdr_t;
|
};
|
||||||
|
|
||||||
/*
|
struct Mempool
|
||||||
** alloc_root_t - Header for the whole pool.
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef struct alloc_root_s
|
|
||||||
{
|
{
|
||||||
alloc_hdr_t *first, /* First header in pool */
|
struct MemBlock *first;
|
||||||
*current; /* Current header */
|
struct MemBlock *current;
|
||||||
} alloc_root_t;
|
};
|
||||||
|
|
||||||
/*
|
static struct MemBlock* createMemBlock()
|
||||||
** root - Pointer to the current pool.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static alloc_root_t *root;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** AllocHdr()
|
|
||||||
**
|
|
||||||
** Private routine to allocate a header and memory block.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static alloc_hdr_t *AllocHdr(void);
|
|
||||||
|
|
||||||
static alloc_hdr_t * AllocHdr()
|
|
||||||
{
|
{
|
||||||
alloc_hdr_t *hdr;
|
struct MemBlock* memBlock = malloc(sizeof(struct MemBlock));
|
||||||
char *block;
|
if (memBlock)
|
||||||
|
{
|
||||||
block = (char *) malloc(ALLOC_BLOCK_SIZE);
|
memBlock->block = malloc(ALLOC_BLOCK_SIZE * sizeof(char));
|
||||||
hdr = (alloc_hdr_t *) malloc(sizeof(alloc_hdr_t));
|
if (memBlock->block == NULL)
|
||||||
|
{
|
||||||
if (hdr == NULL || block == NULL) return(NULL);
|
free(memBlock);
|
||||||
hdr->block = block;
|
return NULL;
|
||||||
hdr->free = block;
|
}
|
||||||
hdr->next = NULL;
|
memBlock->free = memBlock->block;
|
||||||
hdr->end = block + ALLOC_BLOCK_SIZE;
|
memBlock->next = NULL;
|
||||||
|
memBlock->end = memBlock->block + ALLOC_BLOCK_SIZE;
|
||||||
return(hdr);
|
}
|
||||||
|
return memBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
static void deleteMemBlock(struct MemBlock* memBlock)
|
||||||
** AllocInit()
|
|
||||||
**
|
|
||||||
** Create a new memory pool with one block.
|
|
||||||
** Returns pointer to the new pool.
|
|
||||||
*/
|
|
||||||
|
|
||||||
DLLEXPORT alloc_handle_t * AllocInit()
|
|
||||||
{
|
{
|
||||||
alloc_handle_t *newpool;
|
free(memBlock->block);
|
||||||
root = (alloc_root_t *) malloc(sizeof(alloc_root_t));
|
free(memBlock);
|
||||||
if (root == NULL) {
|
|
||||||
return(NULL);
|
|
||||||
}
|
|
||||||
if ( (root->first = AllocHdr()) == NULL) {
|
|
||||||
return(NULL);
|
|
||||||
}
|
|
||||||
root->current = root->first;
|
|
||||||
newpool = (alloc_handle_t *) root;
|
|
||||||
return(newpool);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
struct Mempool * mempool_create()
|
||||||
** Alloc()
|
|
||||||
**
|
|
||||||
** Use as a direct replacement for malloc(). Allocates
|
|
||||||
** memory from the current pool.
|
|
||||||
*/
|
|
||||||
|
|
||||||
DLLEXPORT char *Alloc(long size)
|
|
||||||
{
|
{
|
||||||
alloc_hdr_t *hdr = root->current;
|
struct Mempool *mempool;
|
||||||
char *ptr;
|
mempool = (struct Mempool *)malloc(sizeof(struct Mempool));
|
||||||
|
if (mempool == NULL) return NULL;
|
||||||
|
mempool->first = createMemBlock();
|
||||||
|
mempool->current = mempool->first;
|
||||||
|
if (mempool->first == NULL) return NULL;
|
||||||
|
return mempool;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mempool_delete(struct Mempool *mempool)
|
||||||
|
{
|
||||||
|
if (mempool == NULL) return;
|
||||||
|
while (mempool->first)
|
||||||
|
{
|
||||||
|
mempool->current = mempool->first->next;
|
||||||
|
deleteMemBlock(mempool->first);
|
||||||
|
mempool->first = mempool->current;
|
||||||
|
}
|
||||||
|
free(mempool);
|
||||||
|
mempool = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mempool_reset(struct Mempool *mempool)
|
||||||
|
{
|
||||||
|
mempool->current = mempool->first;
|
||||||
|
mempool->current->free = mempool->current->block;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char * mempool_alloc(struct Mempool *mempool, size_t size)
|
||||||
|
{
|
||||||
|
char* ptr;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Align to 4 byte boundary - should be ok for most machines.
|
** Align to 4 byte boundary - should be ok for most machines.
|
||||||
@@ -124,86 +101,37 @@ DLLEXPORT char *Alloc(long size)
|
|||||||
*/
|
*/
|
||||||
size = (size + 3) & 0xfffffffc;
|
size = (size + 3) & 0xfffffffc;
|
||||||
|
|
||||||
ptr = hdr->free;
|
if (!mempool->current) return NULL;
|
||||||
hdr->free += size;
|
ptr = mempool->current->free;
|
||||||
|
mempool->current->free += size;
|
||||||
|
|
||||||
/* Check if the current block is exhausted. */
|
// Check if the current block is exhausted
|
||||||
|
|
||||||
if (hdr->free >= hdr->end)
|
if (mempool->current->free >= mempool->current->end)
|
||||||
{
|
{
|
||||||
/* Is the next block already allocated? */
|
// Is the next block already allocated?
|
||||||
|
|
||||||
if (hdr->next != NULL)
|
if (mempool->current->next)
|
||||||
{
|
{
|
||||||
/* re-use block */
|
// re-use block
|
||||||
hdr->next->free = hdr->next->block;
|
mempool->current->next->free = mempool->current->next->block;
|
||||||
root->current = hdr->next;
|
mempool->current = mempool->current->next;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* extend the pool with a new block */
|
// extend the pool with a new block
|
||||||
if ( (hdr->next = AllocHdr()) == NULL) return(NULL);
|
mempool->current->next = createMemBlock();
|
||||||
root->current = hdr->next;
|
if (!mempool->current->next) return NULL;
|
||||||
|
mempool->current = mempool->current->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set ptr to the first location in the next block */
|
// set ptr to the first location in the next block
|
||||||
ptr = root->current->free;
|
|
||||||
root->current->free += size;
|
ptr = mempool->current->free;
|
||||||
|
mempool->current->free += size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return pointer to allocated memory. */
|
// Return pointer to allocated memory
|
||||||
|
|
||||||
return(ptr);
|
return ptr;
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** AllocSetPool()
|
|
||||||
**
|
|
||||||
** Change the current pool. Return the old pool.
|
|
||||||
*/
|
|
||||||
|
|
||||||
DLLEXPORT alloc_handle_t * AllocSetPool(alloc_handle_t *newpool)
|
|
||||||
{
|
|
||||||
alloc_handle_t *old = (alloc_handle_t *) root;
|
|
||||||
root = (alloc_root_t *) newpool;
|
|
||||||
return(old);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** AllocReset()
|
|
||||||
**
|
|
||||||
** Reset the current pool for re-use. No memory is freed,
|
|
||||||
** so this is very fast.
|
|
||||||
*/
|
|
||||||
|
|
||||||
DLLEXPORT void AllocReset()
|
|
||||||
{
|
|
||||||
root->current = root->first;
|
|
||||||
root->current->free = root->current->block;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** AllocFreePool()
|
|
||||||
**
|
|
||||||
** Free the memory used by the current pool.
|
|
||||||
** Don't use where AllocReset() could be used.
|
|
||||||
*/
|
|
||||||
|
|
||||||
DLLEXPORT void AllocFreePool()
|
|
||||||
{
|
|
||||||
alloc_hdr_t *tmp,
|
|
||||||
*hdr = root->first;
|
|
||||||
|
|
||||||
while (hdr != NULL)
|
|
||||||
{
|
|
||||||
tmp = hdr->next;
|
|
||||||
free((char *) hdr->block);
|
|
||||||
free((char *) hdr);
|
|
||||||
hdr = tmp;
|
|
||||||
}
|
|
||||||
free((char *) root);
|
|
||||||
root = NULL;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,41 +3,17 @@
|
|||||||
**
|
**
|
||||||
** Header for mempool.c
|
** Header for mempool.c
|
||||||
**
|
**
|
||||||
** The type alloc_handle_t provides an opaque reference to the
|
** A simple pooled memory allocator
|
||||||
** alloc pool - only the alloc routines know its structure.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef MEMPOOL_H
|
#ifndef MEMPOOL_H
|
||||||
#define MEMPOOL_H
|
#define MEMPOOL_H
|
||||||
|
|
||||||
#ifndef DLLEXPORT
|
struct Mempool;
|
||||||
#ifdef DLL
|
|
||||||
#ifdef __cplusplus
|
|
||||||
#define DLLEXPORT extern "C" __declspec(dllexport)
|
|
||||||
#else
|
|
||||||
#define DLLEXPORT __declspec(dllexport) __stdcall
|
|
||||||
#endif
|
|
||||||
#elif defined(CYGWIN)
|
|
||||||
#define DLLEXPORT __stdcall
|
|
||||||
#else
|
|
||||||
#ifdef __cplusplus
|
|
||||||
#define DLLEXPORT
|
|
||||||
#else
|
|
||||||
#define DLLEXPORT
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
struct Mempool * mempool_create();
|
||||||
typedef struct
|
void mempool_delete(struct Mempool *mempool);
|
||||||
{
|
void mempool_reset(struct Mempool *mempool);
|
||||||
long dummy;
|
char * mempool_alloc(struct Mempool *mempool, size_t size);
|
||||||
} alloc_handle_t;
|
|
||||||
|
|
||||||
alloc_handle_t *AllocInit(void);
|
|
||||||
char *Alloc(long);
|
|
||||||
alloc_handle_t *AllocSetPool(alloc_handle_t *);
|
|
||||||
void AllocReset(void);
|
|
||||||
void AllocFreePool(void);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -29,9 +29,9 @@ AUTHOR: L. Rossman
|
|||||||
closequal() -- called from ENcloseQ() in EPANET.C
|
closequal() -- called from ENcloseQ() in EPANET.C
|
||||||
|
|
||||||
Calls are made to:
|
Calls are made to:
|
||||||
AllocInit()
|
mempool_create()
|
||||||
Alloc()
|
mempool_alloc()
|
||||||
AllocFree()
|
mempool_delete()
|
||||||
in MEMPOOL.C to utilize a memory pool to prevent excessive malloc'ing
|
in MEMPOOL.C to utilize a memory pool to prevent excessive malloc'ing
|
||||||
when constantly creating and destroying pipe sub-segments during
|
when constantly creating and destroying pipe sub-segments during
|
||||||
the water quality transport calculations.
|
the water quality transport calculations.
|
||||||
@@ -89,7 +89,7 @@ int openqual(EN_Project *pr)
|
|||||||
|
|
||||||
/* Allocate memory pool for WQ segments */
|
/* Allocate memory pool for WQ segments */
|
||||||
qu->OutOfMemory = FALSE;
|
qu->OutOfMemory = FALSE;
|
||||||
qu->SegPool = AllocInit();
|
qu->SegPool = mempool_create();
|
||||||
if (qu->SegPool == NULL) {
|
if (qu->SegPool == NULL) {
|
||||||
errcode = 101;
|
errcode = 101;
|
||||||
}
|
}
|
||||||
@@ -193,8 +193,7 @@ void initqual(EN_Project *pr)
|
|||||||
|
|
||||||
/* Reset memory pool */
|
/* Reset memory pool */
|
||||||
qu->FreeSeg = NULL;
|
qu->FreeSeg = NULL;
|
||||||
AllocSetPool(qu->SegPool);
|
mempool_reset(qu->SegPool);
|
||||||
AllocReset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize avg. reaction rates */
|
/* Initialize avg. reaction rates */
|
||||||
@@ -438,8 +437,7 @@ int closequal(EN_Project *pr)
|
|||||||
/* Free memory pool */
|
/* Free memory pool */
|
||||||
if (qu->SegPool)
|
if (qu->SegPool)
|
||||||
{
|
{
|
||||||
AllocSetPool(qu->SegPool);
|
mempool_delete(qu->SegPool);
|
||||||
AllocFreePool();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(qu->FirstSeg);
|
free(qu->FirstSeg);
|
||||||
@@ -573,7 +571,6 @@ void transport(EN_Project *pr, long tstep)
|
|||||||
|
|
||||||
/* Repeat until elapsed time equals hydraulic time step */
|
/* Repeat until elapsed time equals hydraulic time step */
|
||||||
|
|
||||||
AllocSetPool(qu->SegPool);
|
|
||||||
qtime = 0;
|
qtime = 0;
|
||||||
while (!qu->OutOfMemory && qtime < tstep) { /* Qstep is quality time step */
|
while (!qu->OutOfMemory && qtime < tstep) { /* Qstep is quality time step */
|
||||||
dt = MIN(qu->Qstep, tstep - qtime); /* Current time step */
|
dt = MIN(qu->Qstep, tstep - qtime); /* Current time step */
|
||||||
@@ -793,7 +790,7 @@ void addseg(EN_Project *pr, int k, double v, double c)
|
|||||||
seg = qu->FreeSeg;
|
seg = qu->FreeSeg;
|
||||||
qu->FreeSeg = seg->prev;
|
qu->FreeSeg = seg->prev;
|
||||||
} else {
|
} else {
|
||||||
seg = (struct Sseg *)Alloc(sizeof(struct Sseg));
|
seg = (struct Sseg *) mempool_alloc(qu->SegPool, sizeof(struct Sseg));
|
||||||
if (seg == NULL) {
|
if (seg == NULL) {
|
||||||
qu->OutOfMemory = TRUE;
|
qu->OutOfMemory = TRUE;
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ AUTHOR: L. Rossman
|
|||||||
|
|
||||||
#include "epanet2.h"
|
#include "epanet2.h"
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
#include "mempool.h"
|
|
||||||
#include "util/errormanager.h"
|
#include "util/errormanager.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -538,6 +537,8 @@ typedef struct s_ActItem /* Action list item */
|
|||||||
} ActItem;
|
} ActItem;
|
||||||
|
|
||||||
|
|
||||||
|
// Forward declaration of the Mempool structure defined in mempool.h
|
||||||
|
struct Mempool;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char
|
char
|
||||||
@@ -578,7 +579,7 @@ typedef struct {
|
|||||||
Qtime; /// Current quality time (sec)
|
Qtime; /// Current quality time (sec)
|
||||||
|
|
||||||
char OutOfMemory; /* Out of memory indicator */
|
char OutOfMemory; /* Out of memory indicator */
|
||||||
alloc_handle_t *SegPool; // Memory pool for water quality segments
|
struct Mempool *SegPool; // Memory pool for water quality segments
|
||||||
|
|
||||||
Pseg FreeSeg; /* Pointer to unused segment */
|
Pseg FreeSeg; /* Pointer to unused segment */
|
||||||
Pseg *FirstSeg, /* First (downstream) segment in each pipe */
|
Pseg *FirstSeg, /* First (downstream) segment in each pipe */
|
||||||
|
|||||||
Reference in New Issue
Block a user