This is Unofficial EPICS BASE Doxygen Site
dbmf.c
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2002 The University of Chicago, as Operator of Argonne
3 * National Laboratory.
4 * Copyright (c) 2002 The Regents of the University of California, as
5 * Operator of Los Alamos National Laboratory.
6 * EPICS BASE is distributed subject to a Software License Agreement found
7 * in file LICENSE that is included with this distribution.
8 \*************************************************************************/
9 /*
10  * Author: Jim Kowalkowski and Marty Kraimer
11  * Date: 4/97
12  *
13  * Intended for applications that create and free requently
14  *
15  */
16 
17 #include <stdlib.h>
18 #include <stddef.h>
19 #include <stdio.h>
20 #include <string.h>
21 
22 #include "valgrind/valgrind.h"
23 
24 #ifndef NVALGRIND
25 /* buffer around allocations to detect out of bounds access */
26 #define REDZONE sizeof(double)
27 #else
28 #define REDZONE 0
29 #endif
30 
31 #include "cantProceed.h"
32 #include "epicsMutex.h"
33 #include "ellLib.h"
34 #include "dbmf.h"
35 /*
36 #define DBMF_FREELIST_DEBUG 1
37 */
38 #ifndef DBMF_FREELIST_DEBUG
39 
40 /*Default values for dblfInit */
41 #define DBMF_SIZE 64
42 #define DBMF_INITIAL_ITEMS 10
43 
44 typedef struct chunkNode {/*control block for each set of chunkItems*/
46  void *pchunk;
47  int nNotFree;
48 }chunkNode;
49 
50 typedef struct itemHeader{
51  void *pnextFree;
53 }itemHeader;
54 
55 typedef struct dbmfPrivate {
58  size_t size;
59  size_t allocSize;
61  size_t chunkSize;
62  int nAlloc;
63  int nFree;
64  int nGtSize;
65  void *freeList;
66 } dbmfPrivate;
68 static dbmfPrivate *pdbmfPvt = NULL;
69 int dbmfDebug=0;
70 
71 int dbmfInit(size_t size, int chunkItems)
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 }
95 
96 
97 void* dbmfMalloc(size_t size)
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 }
158 
159 char * dbmfStrdup(const char *str)
160 {
161  size_t len = strlen(str);
162  char *buf = dbmfMalloc(len + 1); /* FIXME Can return NULL */
163 
164  return strcpy(buf, str);
165 }
166 
167 char * dbmfStrndup(const char *str, size_t len)
168 {
169  char *buf = dbmfMalloc(len + 1); /* FIXME Can return NULL */
170 
171  buf[len] = '\0';
172  return strncpy(buf, str, len);
173 }
174 
175 void dbmfFree(void* mem)
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 }
204 
205 int dbmfShow(int level)
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 }
240 
241 void dbmfFreeChunks(void)
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 }
267 
268 #else /* DBMF_FREELIST_DEBUG */
269 
270 int dbmfInit(size_t size, int chunkItems)
271 { return 0; }
272 
273 void* dbmfMalloc(size_t size)
274 { return malloc(size); }
275 
276 char * dbmfStrdup(const char *str)
277 { return strdup((char*)str); }
278 
279 void dbmfFree(void* mem)
280 { free(mem); }
281 
282 int dbmfShow(int level)
283 { return 0; }
284 
285 void dbmfFreeChunks(void) {}
286 
287 #endif /* DBMF_FREELIST_DEBUG */
288 
289 char * dbmfStrcat3(const char *lhs, const char *mid, const char *rhs)
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 }
298 
struct chunkNode chunkNode
int nAlloc
Definition: dbmf.c:62
char * dbmfStrdup(const char *str)
Duplicate a string.
Definition: dbmf.c:159
struct itemHeader itemHeader
#define ellCount(PLIST)
Report the number of nodes in a list.
Definition: ellLib.h:84
dbmfPrivate dbmfPvt
Definition: dbmf.c:67
int i
Definition: scan.c:967
ELLLIST chunkList
Definition: dbmf.c:56
char * dbmfStrcat3(const char *lhs, const char *mid, const char *rhs)
Concatenate three strings.
Definition: dbmf.c:289
char * strdup(const char *)
int dbmfShow(int level)
Show the status of the dbmf memory pool.
Definition: dbmf.c:205
#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 str(v)
#define DBMF_INITIAL_ITEMS
Definition: dbmf.c:42
void epicsStdCall epicsMutexUnlock(epicsMutexId pmutexNode)
Release the semaphore.
Definition: epicsMutex.cpp:140
void dbmfFreeChunks(void)
Free all chunks that contain only free items.
Definition: dbmf.c:241
A library to manage storage that is allocated and quickly freed.
void * pnextFree
Definition: dbmf.c:51
#define VALGRIND_CREATE_MEMPOOL(pool, rzB, is_zeroed)
Definition: valgrind.h:6470
A doubly-linked list library.
void ellAdd(ELLLIST *pList, ELLNODE *pNode)
Adds a node to the end of a list.
Definition: ellLib.c:24
#define ellNext(PNODE)
Find the next node in list.
Definition: ellLib.h:99
APIs for the epicsMutex mutual exclusion semaphore.
void dbmfFree(void *mem)
Free the memory allocated by dbmfMalloc.
Definition: dbmf.c:175
#define VALGRIND_MEMPOOL_ALLOC(pool, addr, size)
Definition: valgrind.h:6480
int nNotFree
Definition: dbmf.c:47
size_t size
Definition: dbmf.c:58
List node type.
Definition: ellLib.h:45
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 ellInit(PLIST)
Initialize a list type.
Definition: ellLib.h:76
#define REDZONE
Definition: dbmf.c:26
LIBCOM_API void cantProceed(const char *msg,...)
Definition: cantProceed.c:54
epicsMutexId lock
Definition: dbmf.c:57
Routines for code that can&#39;t continue or return after an error.
#define VALGRIND_MEMPOOL_FREE(pool, addr)
Definition: valgrind.h:6485
size_t chunkSize
Definition: dbmf.c:61
List header type.
Definition: ellLib.h:56
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
void ellDelete(ELLLIST *pList, ELLNODE *pNode)
Deletes a node from a list.
Definition: ellLib.c:75
char * dbmfStrndup(const char *str, size_t len)
Duplicate a string (up to len bytes).
Definition: dbmf.c:167
void * dbmfMalloc(size_t size)
Allocate memory.
Definition: dbmf.c:97
struct dbmfPrivate dbmfPrivate
size_t allocSize
Definition: dbmf.c:59
#define ellFirst(PLIST)
Find the first node in list.
Definition: ellLib.h:89