This is Unofficial EPICS BASE Doxygen Site
dbmf.h File Reference

A library to manage storage that is allocated and quickly freed. More...

#include <stdlib.h>
#include "libComAPI.h"
+ Include dependency graph for dbmf.h:
+ This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

LIBCOM_API int dbmfInit (size_t size, int chunkItems)
 Initialize the facility. More...
 
LIBCOM_API void * dbmfMalloc (size_t bytes)
 Allocate memory. More...
 
LIBCOM_API char * dbmfStrdup (const char *str)
 Duplicate a string. More...
 
LIBCOM_API char * dbmfStrndup (const char *str, size_t len)
 Duplicate a string (up to len bytes). More...
 
LIBCOM_API char * dbmfStrcat3 (const char *lhs, const char *mid, const char *rhs)
 Concatenate three strings. More...
 
LIBCOM_API void dbmfFree (void *bytes)
 Free the memory allocated by dbmfMalloc. More...
 
LIBCOM_API void dbmfFreeChunks (void)
 Free all chunks that contain only free items. More...
 
LIBCOM_API int dbmfShow (int level)
 Show the status of the dbmf memory pool. More...
 

Detailed Description

A library to manage storage that is allocated and quickly freed.

Author
Jim Kowalkowski, Marty Kraimer

Database Macro/Free describes a facility that prevents memory fragmentation when temporary storage is being allocated and freed a short time later, at the same time that much longer-lived storage is also being allocated, such as when parsing items for the IOC database while also creating records.

Routines whin iocCore like dbLoadDatabase() have the following attributes:

  • They repeatedly call malloc() followed soon afterwards by a call to free() the temporaryily allocated storage.
  • Between those calls to malloc() and free(), additional calls to malloc() are made that do NOT have an associated free().
Note
In some environment, e.g. vxWorks, this behavior causes severe memory fragmentation.
This facility should NOT be used by code that allocates storage and then keeps it for a considerable period of time before releasing. Such code should consider using the freeList library.

Definition in file dbmf.h.

Function Documentation

LIBCOM_API void dbmfFree ( void *  bytes)

Free the memory allocated by dbmfMalloc.

Parameters
bytesPointer to memory obtained from dbmfMalloc(), dbmfStrdup(), dbmfStrndup() or dbmfStrcat3().

Definition at line 175 of file dbmf.c.

176 {
177  char *pmem = (char *)mem;
178  chunkNode *pchunkNode;
179  itemHeader *pitemHeader;
180 
181  if(!mem) return;
182  if(!pdbmfPvt) {
183  printf("dbmfFree called but dbmfInit never called\n");
184  return;
185  }
186  VALGRIND_MEMPOOL_FREE(pdbmfPvt, mem);
187  pmem -= sizeof(itemHeader) + REDZONE;
188  epicsMutexMustLock(pdbmfPvt->lock);
189  pitemHeader = (itemHeader *)pmem;
190  if(!pitemHeader->pchunkNode) {
191  if(dbmfDebug) printf("dbmfGree: mem %p\n",pmem);
192  free((void *)pmem); pdbmfPvt->nAlloc--;
193  }else {
194  void **pfreeList = &pdbmfPvt->freeList;
195  void **pnextFree = &pitemHeader->pnextFree;
196 
197  pchunkNode = pitemHeader->pchunkNode;
198  pchunkNode->nNotFree--;
199  *pnextFree = *pfreeList; *pfreeList = pnextFree;
200  pdbmfPvt->nAlloc--; pdbmfPvt->nFree++;
201  }
202  epicsMutexUnlock(pdbmfPvt->lock);
203 }
int nAlloc
Definition: dbmf.c:62
struct itemHeader itemHeader
#define printf
Definition: epicsStdio.h:41
void epicsStdCall epicsMutexUnlock(epicsMutexId pmutexNode)
Release the semaphore.
Definition: epicsMutex.cpp:140
void * pnextFree
Definition: dbmf.c:51
int nNotFree
Definition: dbmf.c:47
int nFree
Definition: dbmf.c:63
int dbmfDebug
Definition: dbmf.c:69
Definition: dbmf.c:44
void * freeList
Definition: dbmf.c:65
#define REDZONE
Definition: dbmf.c:26
epicsMutexId lock
Definition: dbmf.c:57
#define VALGRIND_MEMPOOL_FREE(pool, addr)
Definition: valgrind.h:6485
chunkNode * pchunkNode
Definition: dbmf.c:52
#define epicsMutexMustLock(ID)
Claim a semaphore (see epicsMutexLock()).
Definition: epicsMutex.h:214
LIBCOM_API void dbmfFreeChunks ( void  )

Free all chunks that contain only free items.

Definition at line 241 of file dbmf.c.

242 {
243  chunkNode *pchunkNode;
244  chunkNode *pnext;;
245 
246  if(!pdbmfPvt) {
247  printf("dbmfFreeChunks called but dbmfInit never called\n");
248  return;
249  }
250  epicsMutexMustLock(pdbmfPvt->lock);
251  if(pdbmfPvt->nFree
252  != (pdbmfPvt->chunkItems * ellCount(&pdbmfPvt->chunkList))) {
253  printf("dbmfFinish: not all free\n");
254  epicsMutexUnlock(pdbmfPvt->lock);
255  return;
256  }
257  pchunkNode = (chunkNode *)ellFirst(&pdbmfPvt->chunkList);
258  while(pchunkNode) {
259  pnext = (chunkNode *)ellNext(&pchunkNode->node);
260  ellDelete(&pdbmfPvt->chunkList,&pchunkNode->node);
261  free(pchunkNode->pchunk);
262  pchunkNode = pnext;
263  }
264  pdbmfPvt->nFree = 0; pdbmfPvt->freeList = NULL;
265  epicsMutexUnlock(pdbmfPvt->lock);
266 }
#define ellCount(PLIST)
Report the number of nodes in a list.
Definition: ellLib.h:84
ELLLIST chunkList
Definition: dbmf.c:56
#define printf
Definition: epicsStdio.h:41
#define NULL
Definition: catime.c:38
void epicsStdCall epicsMutexUnlock(epicsMutexId pmutexNode)
Release the semaphore.
Definition: epicsMutex.cpp:140
#define ellNext(PNODE)
Find the next node in list.
Definition: ellLib.h:99
int chunkItems
Definition: dbmf.c:60
int nFree
Definition: dbmf.c:63
void * pchunk
Definition: dbmf.c:46
Definition: dbmf.c:44
void * freeList
Definition: dbmf.c:65
epicsMutexId lock
Definition: dbmf.c:57
ELLNODE node
Definition: dbmf.c:45
#define epicsMutexMustLock(ID)
Claim a semaphore (see epicsMutexLock()).
Definition: epicsMutex.h:214
void ellDelete(ELLLIST *pList, ELLNODE *pNode)
Deletes a node from a list.
Definition: ellLib.c:75
#define ellFirst(PLIST)
Find the first node in list.
Definition: ellLib.h:89
LIBCOM_API int dbmfInit ( size_t  size,
int  chunkItems 
)

Initialize the facility.

Parameters
sizeThe maximum size request from dbmfMalloc() that will be allocated from the dbmf pool (Size is always made a multiple of 8).
chunkItemsEach time malloc() must be called size*chunkItems bytes are allocated.
Returns
0 on success, -1 if already initialized
Note
If dbmfInit() is not called before one of the other routines then it is automatically called with size=64 and chunkItems=10

Definition at line 71 of file dbmf.c.

72 {
73  if(pdbmfPvt) {
74  printf("dbmfInit: Already initialized\n");
75  return(-1);
76  }
77  pdbmfPvt = &dbmfPvt;
78  ellInit(&pdbmfPvt->chunkList);
79  pdbmfPvt->lock = epicsMutexMustCreate();
80  /*allign to at least a double*/
81  pdbmfPvt->size = size + size%sizeof(double);
82  /* layout is
83  * | itemHeader | REDZONE | size | REDZONE |
84  */
85  pdbmfPvt->allocSize = pdbmfPvt->size + sizeof(itemHeader) + 2*REDZONE;
86  pdbmfPvt->chunkItems = chunkItems;
87  pdbmfPvt->chunkSize = pdbmfPvt->allocSize * pdbmfPvt->chunkItems;
88  pdbmfPvt->nAlloc = 0;
89  pdbmfPvt->nFree = 0;
90  pdbmfPvt->nGtSize = 0;
91  pdbmfPvt->freeList = NULL;
92  VALGRIND_CREATE_MEMPOOL(pdbmfPvt, REDZONE, 0);
93  return(0);
94 }
int nAlloc
Definition: dbmf.c:62
struct itemHeader itemHeader
dbmfPrivate dbmfPvt
Definition: dbmf.c:67
ELLLIST chunkList
Definition: dbmf.c:56
#define printf
Definition: epicsStdio.h:41
#define epicsMutexMustCreate()
Create an epicsMutex semaphore for use from C code.
Definition: epicsMutex.h:179
#define NULL
Definition: catime.c:38
#define VALGRIND_CREATE_MEMPOOL(pool, rzB, is_zeroed)
Definition: valgrind.h:6470
size_t size
Definition: dbmf.c:58
int chunkItems
Definition: dbmf.c:60
int nFree
Definition: dbmf.c:63
void * freeList
Definition: dbmf.c:65
#define ellInit(PLIST)
Initialize a list type.
Definition: ellLib.h:76
#define REDZONE
Definition: dbmf.c:26
epicsMutexId lock
Definition: dbmf.c:57
size_t chunkSize
Definition: dbmf.c:61
int nGtSize
Definition: dbmf.c:64
size_t allocSize
Definition: dbmf.c:59
LIBCOM_API void* dbmfMalloc ( size_t  bytes)

Allocate memory.

Parameters
bytesIf bytes > size then malloc() is used to allocate the memory.
Returns
Pointer to the newly-allocated memory, or NULL on failure.

Definition at line 97 of file dbmf.c.

98 {
99  void **pnextFree;
100  void **pfreeList;
101  char *pmem = NULL;
102  chunkNode *pchunkNode;
103  itemHeader *pitemHeader;
104 
105  if(!pdbmfPvt) dbmfInit(DBMF_SIZE,DBMF_INITIAL_ITEMS);
106  epicsMutexMustLock(pdbmfPvt->lock);
107  pfreeList = &pdbmfPvt->freeList;
108  if(*pfreeList == NULL) {
109  int i;
110  size_t nbytesTotal;
111 
112  if(dbmfDebug) printf("dbmfMalloc allocating new storage\n");
113  nbytesTotal = pdbmfPvt->chunkSize + sizeof(chunkNode);
114  pmem = (char *)malloc(nbytesTotal);
115  if(!pmem) {
116  epicsMutexUnlock(pdbmfPvt->lock);
117  cantProceed("dbmfMalloc malloc failed\n");
118  return(NULL);
119  }
120  pchunkNode = (chunkNode *)(pmem + pdbmfPvt->chunkSize);
121  pchunkNode->pchunk = pmem;
122  pchunkNode->nNotFree=0;
123  ellAdd(&pdbmfPvt->chunkList,&pchunkNode->node);
124  for(i=0; i<pdbmfPvt->chunkItems; i++) {
125  pitemHeader = (itemHeader *)pmem;
126  pitemHeader->pchunkNode = pchunkNode;
127  pnextFree = &pitemHeader->pnextFree;
128  *pnextFree = *pfreeList; *pfreeList = (void *)pmem;
129  pdbmfPvt->nFree++;
130  pmem += pdbmfPvt->allocSize;
131  }
132  }
133  if(size<=pdbmfPvt->size) {
134  pnextFree = *pfreeList; *pfreeList = *pnextFree;
135  pmem = (void *)pnextFree;
136  pdbmfPvt->nAlloc++; pdbmfPvt->nFree--;
137  pitemHeader = (itemHeader *)pnextFree;
138  pitemHeader->pchunkNode->nNotFree += 1;
139  } else {
140  pmem = malloc(sizeof(itemHeader) + 2*REDZONE + size);
141  if(!pmem) {
142  epicsMutexUnlock(pdbmfPvt->lock);
143  cantProceed("dbmfMalloc malloc failed\n");
144  return(NULL);
145  }
146  pdbmfPvt->nAlloc++;
147  pdbmfPvt->nGtSize++;
148  pitemHeader = (itemHeader *)pmem;
149  pitemHeader->pchunkNode = NULL; /* not part of free list */
150  if(dbmfDebug) printf("dbmfMalloc: size %lu mem %p\n",
151  (unsigned long)size,pmem);
152  }
153  epicsMutexUnlock(pdbmfPvt->lock);
154  pmem += sizeof(itemHeader) + REDZONE;
155  VALGRIND_MEMPOOL_ALLOC(pdbmfPvt, pmem, size);
156  return((void *)pmem);
157 }
struct chunkNode chunkNode
int nAlloc
Definition: dbmf.c:62
struct itemHeader itemHeader
int i
Definition: scan.c:967
ELLLIST chunkList
Definition: dbmf.c:56
#define printf
Definition: epicsStdio.h:41
#define NULL
Definition: catime.c:38
#define DBMF_INITIAL_ITEMS
Definition: dbmf.c:42
void epicsStdCall epicsMutexUnlock(epicsMutexId pmutexNode)
Release the semaphore.
Definition: epicsMutex.cpp:140
void * pnextFree
Definition: dbmf.c:51
void ellAdd(ELLLIST *pList, ELLNODE *pNode)
Adds a node to the end of a list.
Definition: ellLib.c:24
#define VALGRIND_MEMPOOL_ALLOC(pool, addr, size)
Definition: valgrind.h:6480
int nNotFree
Definition: dbmf.c:47
int dbmfInit(size_t size, int chunkItems)
Initialize the facility.
Definition: dbmf.c:71
int chunkItems
Definition: dbmf.c:60
int nFree
Definition: dbmf.c:63
int dbmfDebug
Definition: dbmf.c:69
void * pchunk
Definition: dbmf.c:46
Definition: dbmf.c:44
void * freeList
Definition: dbmf.c:65
#define REDZONE
Definition: dbmf.c:26
LIBCOM_API void cantProceed(const char *msg,...)
Definition: cantProceed.c:54
epicsMutexId lock
Definition: dbmf.c:57
size_t chunkSize
Definition: dbmf.c:61
ELLNODE node
Definition: dbmf.c:45
chunkNode * pchunkNode
Definition: dbmf.c:52
int nGtSize
Definition: dbmf.c:64
#define epicsMutexMustLock(ID)
Claim a semaphore (see epicsMutexLock()).
Definition: epicsMutex.h:214
#define DBMF_SIZE
Definition: dbmf.c:41
size_t allocSize
Definition: dbmf.c:59
LIBCOM_API int dbmfShow ( int  level)

Show the status of the dbmf memory pool.

Parameters
levelDetail level.
Returns
0.

Definition at line 205 of file dbmf.c.

206 {
207  if(pdbmfPvt==NULL) {
208  printf("Never initialized\n");
209  return(0);
210  }
211  printf("size %lu allocSize %lu chunkItems %d ",
212  (unsigned long)pdbmfPvt->size,
213  (unsigned long)pdbmfPvt->allocSize,pdbmfPvt->chunkItems);
214  printf("nAlloc %d nFree %d nChunks %d nGtSize %d\n",
215  pdbmfPvt->nAlloc,pdbmfPvt->nFree,
216  ellCount(&pdbmfPvt->chunkList),pdbmfPvt->nGtSize);
217  if(level>0) {
218  chunkNode *pchunkNode;
219 
220  pchunkNode = (chunkNode *)ellFirst(&pdbmfPvt->chunkList);
221  while(pchunkNode) {
222  printf("pchunkNode %p nNotFree %d\n",
223  (void*)pchunkNode,pchunkNode->nNotFree);
224  pchunkNode = (chunkNode *)ellNext(&pchunkNode->node);
225  }
226  }
227  if(level>1) {
228  void **pnextFree;;
229 
230  epicsMutexMustLock(pdbmfPvt->lock);
231  pnextFree = (void**)pdbmfPvt->freeList;
232  while(pnextFree) {
233  printf("%p\n",*pnextFree);
234  pnextFree = (void**)*pnextFree;
235  }
236  epicsMutexUnlock(pdbmfPvt->lock);
237  }
238  return(0);
239 }
int nAlloc
Definition: dbmf.c:62
#define ellCount(PLIST)
Report the number of nodes in a list.
Definition: ellLib.h:84
ELLLIST chunkList
Definition: dbmf.c:56
#define printf
Definition: epicsStdio.h:41
#define NULL
Definition: catime.c:38
void epicsStdCall epicsMutexUnlock(epicsMutexId pmutexNode)
Release the semaphore.
Definition: epicsMutex.cpp:140
#define ellNext(PNODE)
Find the next node in list.
Definition: ellLib.h:99
int nNotFree
Definition: dbmf.c:47
size_t size
Definition: dbmf.c:58
int chunkItems
Definition: dbmf.c:60
int nFree
Definition: dbmf.c:63
Definition: dbmf.c:44
void * freeList
Definition: dbmf.c:65
epicsMutexId lock
Definition: dbmf.c:57
ELLNODE node
Definition: dbmf.c:45
int nGtSize
Definition: dbmf.c:64
#define epicsMutexMustLock(ID)
Claim a semaphore (see epicsMutexLock()).
Definition: epicsMutex.h:214
size_t allocSize
Definition: dbmf.c:59
#define ellFirst(PLIST)
Find the first node in list.
Definition: ellLib.h:89
LIBCOM_API char* dbmfStrcat3 ( const char *  lhs,
const char *  mid,
const char *  rhs 
)

Concatenate three strings.

Returns a pointer to a null-terminated string made by concatenating the three input strings.

Parameters
lhsStart string to which the others get concatenated to (left part).
midNext string to be concatenated to the lhs (mid part).
rhsLast string to be concatenated to the lhs+mid (right part).
Returns
A pointer to the new string, or NULL on failure.

Definition at line 289 of file dbmf.c.

290 {
291  size_t len = strlen(lhs) + strlen(mid) + strlen(rhs) + 1;
292  char *buf = dbmfMalloc(len);
293  strcpy(buf, lhs);
294  strcat(buf, mid);
295  strcat(buf, rhs);
296  return buf;
297 }
void * dbmfMalloc(size_t size)
Allocate memory.
Definition: dbmf.c:97
LIBCOM_API char* dbmfStrdup ( const char *  str)

Duplicate a string.

Create a copy of the input string.

Parameters
strPointer to the null-terminated string to be copied.
Returns
A pointer to the new copy, or NULL on failure.

Definition at line 159 of file dbmf.c.

160 {
161  size_t len = strlen(str);
162  char *buf = dbmfMalloc(len + 1); /* FIXME Can return NULL */
163 
164  return strcpy(buf, str);
165 }
#define str(v)
void * dbmfMalloc(size_t size)
Allocate memory.
Definition: dbmf.c:97
LIBCOM_API char* dbmfStrndup ( const char *  str,
size_t  len 
)

Duplicate a string (up to len bytes).

Copy at most len bytes of the input string into a new buffer. If no nil terminator is seen in the first len bytes a nil terminator is added.

Parameters
strPointer to the null-terminated string to be copied.
lenMax number of bytes to copy.
Returns
A pointer to the new string, or NULL on failure.

Definition at line 167 of file dbmf.c.

168 {
169  char *buf = dbmfMalloc(len + 1); /* FIXME Can return NULL */
170 
171  buf[len] = '\0';
172  return strncpy(buf, str, len);
173 }
#define str(v)
void * dbmfMalloc(size_t size)
Allocate memory.
Definition: dbmf.c:97