e34b6c5c0c
Should be non-functional, except for some error message strings.
300 lines
8.3 KiB
C
300 lines
8.3 KiB
C
/*************************************************************************\
|
|
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
|
* National Laboratory.
|
|
* Copyright (c) 2002 The Regents of the University of California, as
|
|
* Operator of Los Alamos National Laboratory.
|
|
* SPDX-License-Identifier: EPICS
|
|
* EPICS BASE is distributed subject to a Software License Agreement found
|
|
* in file LICENSE that is included with this distribution.
|
|
\*************************************************************************/
|
|
/*
|
|
* Author: Jim Kowalkowski and Marty Kraimer
|
|
* Date: 4/97
|
|
*
|
|
* Intended for applications that create and free frequently
|
|
*
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "valgrind/valgrind.h"
|
|
|
|
#ifndef NVALGRIND
|
|
/* buffer around allocations to detect out of bounds access */
|
|
#define REDZONE sizeof(double)
|
|
#else
|
|
#define REDZONE 0
|
|
#endif
|
|
|
|
#include "cantProceed.h"
|
|
#include "epicsMutex.h"
|
|
#include "ellLib.h"
|
|
#include "dbmf.h"
|
|
/*
|
|
#define DBMF_FREELIST_DEBUG 1
|
|
*/
|
|
#ifndef DBMF_FREELIST_DEBUG
|
|
|
|
/*Default values for dblfInit */
|
|
#define DBMF_SIZE 64
|
|
#define DBMF_INITIAL_ITEMS 10
|
|
|
|
typedef struct chunkNode {/*control block for each set of chunkItems*/
|
|
ELLNODE node;
|
|
void *pchunk;
|
|
int nNotFree;
|
|
}chunkNode;
|
|
|
|
typedef struct itemHeader{
|
|
void *pnextFree;
|
|
chunkNode *pchunkNode;
|
|
}itemHeader;
|
|
|
|
typedef struct dbmfPrivate {
|
|
ELLLIST chunkList;
|
|
epicsMutexId lock;
|
|
size_t size;
|
|
size_t allocSize;
|
|
int chunkItems;
|
|
size_t chunkSize;
|
|
int nAlloc;
|
|
int nFree;
|
|
int nGtSize;
|
|
void *freeList;
|
|
} dbmfPrivate;
|
|
dbmfPrivate dbmfPvt;
|
|
static dbmfPrivate *pdbmfPvt = NULL;
|
|
int dbmfDebug=0;
|
|
|
|
int dbmfInit(size_t size, int chunkItems)
|
|
{
|
|
if(pdbmfPvt) {
|
|
printf("dbmfInit: Already initialized\n");
|
|
return(-1);
|
|
}
|
|
pdbmfPvt = &dbmfPvt;
|
|
ellInit(&pdbmfPvt->chunkList);
|
|
pdbmfPvt->lock = epicsMutexMustCreate();
|
|
/*allign to at least a double*/
|
|
pdbmfPvt->size = size + size%sizeof(double);
|
|
/* layout is
|
|
* | itemHeader | REDZONE | size | REDZONE |
|
|
*/
|
|
pdbmfPvt->allocSize = pdbmfPvt->size + sizeof(itemHeader) + 2*REDZONE;
|
|
pdbmfPvt->chunkItems = chunkItems;
|
|
pdbmfPvt->chunkSize = pdbmfPvt->allocSize * pdbmfPvt->chunkItems;
|
|
pdbmfPvt->nAlloc = 0;
|
|
pdbmfPvt->nFree = 0;
|
|
pdbmfPvt->nGtSize = 0;
|
|
pdbmfPvt->freeList = NULL;
|
|
VALGRIND_CREATE_MEMPOOL(pdbmfPvt, REDZONE, 0);
|
|
return(0);
|
|
}
|
|
|
|
|
|
void* dbmfMalloc(size_t size)
|
|
{
|
|
void **pnextFree;
|
|
void **pfreeList;
|
|
char *pmem = NULL;
|
|
chunkNode *pchunkNode;
|
|
itemHeader *pitemHeader;
|
|
|
|
if(!pdbmfPvt) dbmfInit(DBMF_SIZE,DBMF_INITIAL_ITEMS);
|
|
epicsMutexMustLock(pdbmfPvt->lock);
|
|
pfreeList = &pdbmfPvt->freeList;
|
|
if(*pfreeList == NULL) {
|
|
int i;
|
|
size_t nbytesTotal;
|
|
|
|
if(dbmfDebug) printf("dbmfMalloc allocating new storage\n");
|
|
nbytesTotal = pdbmfPvt->chunkSize + sizeof(chunkNode);
|
|
pmem = (char *)malloc(nbytesTotal);
|
|
if(!pmem) {
|
|
epicsMutexUnlock(pdbmfPvt->lock);
|
|
cantProceed("dbmfMalloc malloc failed\n");
|
|
return(NULL);
|
|
}
|
|
pchunkNode = (chunkNode *)(pmem + pdbmfPvt->chunkSize);
|
|
pchunkNode->pchunk = pmem;
|
|
pchunkNode->nNotFree=0;
|
|
ellAdd(&pdbmfPvt->chunkList,&pchunkNode->node);
|
|
for(i=0; i<pdbmfPvt->chunkItems; i++) {
|
|
pitemHeader = (itemHeader *)pmem;
|
|
pitemHeader->pchunkNode = pchunkNode;
|
|
pnextFree = &pitemHeader->pnextFree;
|
|
*pnextFree = *pfreeList; *pfreeList = (void *)pmem;
|
|
pdbmfPvt->nFree++;
|
|
pmem += pdbmfPvt->allocSize;
|
|
}
|
|
}
|
|
if(size<=pdbmfPvt->size) {
|
|
pnextFree = *pfreeList; *pfreeList = *pnextFree;
|
|
pmem = (void *)pnextFree;
|
|
pdbmfPvt->nAlloc++; pdbmfPvt->nFree--;
|
|
pitemHeader = (itemHeader *)pnextFree;
|
|
pitemHeader->pchunkNode->nNotFree += 1;
|
|
} else {
|
|
pmem = malloc(sizeof(itemHeader) + 2*REDZONE + size);
|
|
if(!pmem) {
|
|
epicsMutexUnlock(pdbmfPvt->lock);
|
|
cantProceed("dbmfMalloc malloc failed\n");
|
|
return(NULL);
|
|
}
|
|
pdbmfPvt->nAlloc++;
|
|
pdbmfPvt->nGtSize++;
|
|
pitemHeader = (itemHeader *)pmem;
|
|
pitemHeader->pchunkNode = NULL; /* not part of free list */
|
|
if(dbmfDebug) printf("dbmfMalloc: size %lu mem %p\n",
|
|
(unsigned long)size,pmem);
|
|
}
|
|
epicsMutexUnlock(pdbmfPvt->lock);
|
|
pmem += sizeof(itemHeader) + REDZONE;
|
|
VALGRIND_MEMPOOL_ALLOC(pdbmfPvt, pmem, size);
|
|
return((void *)pmem);
|
|
}
|
|
|
|
char * dbmfStrdup(const char *str)
|
|
{
|
|
size_t len = strlen(str);
|
|
char *buf = dbmfMalloc(len + 1); /* FIXME Can return NULL */
|
|
|
|
return strcpy(buf, str);
|
|
}
|
|
|
|
char * dbmfStrndup(const char *str, size_t len)
|
|
{
|
|
char *buf = dbmfMalloc(len + 1); /* FIXME Can return NULL */
|
|
|
|
buf[len] = '\0';
|
|
return strncpy(buf, str, len);
|
|
}
|
|
|
|
void dbmfFree(void* mem)
|
|
{
|
|
char *pmem = (char *)mem;
|
|
chunkNode *pchunkNode;
|
|
itemHeader *pitemHeader;
|
|
|
|
if(!mem) return;
|
|
if(!pdbmfPvt) {
|
|
printf("dbmfFree called but dbmfInit never called\n");
|
|
return;
|
|
}
|
|
VALGRIND_MEMPOOL_FREE(pdbmfPvt, mem);
|
|
pmem -= sizeof(itemHeader) + REDZONE;
|
|
epicsMutexMustLock(pdbmfPvt->lock);
|
|
pitemHeader = (itemHeader *)pmem;
|
|
if(!pitemHeader->pchunkNode) {
|
|
if(dbmfDebug) printf("dbmfGree: mem %p\n",pmem);
|
|
free((void *)pmem); pdbmfPvt->nAlloc--;
|
|
}else {
|
|
void **pfreeList = &pdbmfPvt->freeList;
|
|
void **pnextFree = &pitemHeader->pnextFree;
|
|
|
|
pchunkNode = pitemHeader->pchunkNode;
|
|
pchunkNode->nNotFree--;
|
|
*pnextFree = *pfreeList; *pfreeList = pnextFree;
|
|
pdbmfPvt->nAlloc--; pdbmfPvt->nFree++;
|
|
}
|
|
epicsMutexUnlock(pdbmfPvt->lock);
|
|
}
|
|
|
|
int dbmfShow(int level)
|
|
{
|
|
if(pdbmfPvt==NULL) {
|
|
printf("Never initialized\n");
|
|
return(0);
|
|
}
|
|
printf("size %lu allocSize %lu chunkItems %d ",
|
|
(unsigned long)pdbmfPvt->size,
|
|
(unsigned long)pdbmfPvt->allocSize,pdbmfPvt->chunkItems);
|
|
printf("nAlloc %d nFree %d nChunks %d nGtSize %d\n",
|
|
pdbmfPvt->nAlloc,pdbmfPvt->nFree,
|
|
ellCount(&pdbmfPvt->chunkList),pdbmfPvt->nGtSize);
|
|
if(level>0) {
|
|
chunkNode *pchunkNode;
|
|
|
|
pchunkNode = (chunkNode *)ellFirst(&pdbmfPvt->chunkList);
|
|
while(pchunkNode) {
|
|
printf("pchunkNode %p nNotFree %d\n",
|
|
(void*)pchunkNode,pchunkNode->nNotFree);
|
|
pchunkNode = (chunkNode *)ellNext(&pchunkNode->node);
|
|
}
|
|
}
|
|
if(level>1) {
|
|
void **pnextFree;;
|
|
|
|
epicsMutexMustLock(pdbmfPvt->lock);
|
|
pnextFree = (void**)pdbmfPvt->freeList;
|
|
while(pnextFree) {
|
|
printf("%p\n",*pnextFree);
|
|
pnextFree = (void**)*pnextFree;
|
|
}
|
|
epicsMutexUnlock(pdbmfPvt->lock);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
void dbmfFreeChunks(void)
|
|
{
|
|
chunkNode *pchunkNode;
|
|
chunkNode *pnext;;
|
|
|
|
if(!pdbmfPvt) {
|
|
printf("dbmfFreeChunks called but dbmfInit never called\n");
|
|
return;
|
|
}
|
|
epicsMutexMustLock(pdbmfPvt->lock);
|
|
if(pdbmfPvt->nFree
|
|
!= (pdbmfPvt->chunkItems * ellCount(&pdbmfPvt->chunkList))) {
|
|
printf("dbmfFinish: not all free\n");
|
|
epicsMutexUnlock(pdbmfPvt->lock);
|
|
return;
|
|
}
|
|
pchunkNode = (chunkNode *)ellFirst(&pdbmfPvt->chunkList);
|
|
while(pchunkNode) {
|
|
pnext = (chunkNode *)ellNext(&pchunkNode->node);
|
|
ellDelete(&pdbmfPvt->chunkList,&pchunkNode->node);
|
|
free(pchunkNode->pchunk);
|
|
pchunkNode = pnext;
|
|
}
|
|
pdbmfPvt->nFree = 0; pdbmfPvt->freeList = NULL;
|
|
epicsMutexUnlock(pdbmfPvt->lock);
|
|
}
|
|
|
|
#else /* DBMF_FREELIST_DEBUG */
|
|
|
|
int dbmfInit(size_t size, int chunkItems)
|
|
{ return 0; }
|
|
|
|
void* dbmfMalloc(size_t size)
|
|
{ return malloc(size); }
|
|
|
|
char * dbmfStrdup(const char *str)
|
|
{ return strdup((char*)str); }
|
|
|
|
void dbmfFree(void* mem)
|
|
{ free(mem); }
|
|
|
|
int dbmfShow(int level)
|
|
{ return 0; }
|
|
|
|
void dbmfFreeChunks(void) {}
|
|
|
|
#endif /* DBMF_FREELIST_DEBUG */
|
|
|
|
char * dbmfStrcat3(const char *lhs, const char *mid, const char *rhs)
|
|
{
|
|
size_t len = strlen(lhs) + strlen(mid) + strlen(rhs) + 1;
|
|
char *buf = dbmfMalloc(len);
|
|
strcpy(buf, lhs);
|
|
strcat(buf, mid);
|
|
strcat(buf, rhs);
|
|
return buf;
|
|
}
|
|
|