Version 6.3
Copyright © 2005 - 2012 Lowell D. Thomas
APG
  … ABNF Parser Generator
All Data Structures Files Functions Variables Typedefs Macros Pages
Memory.c
Go to the documentation of this file.
1 /*******************************************************************************
2  APG Version 6.3
3  Copyright (C) 2005 - 2012 Lowell D. Thomas, all rights reserved
4 
5  author: Lowell D. Thomas
6  email: lowell@coasttocoastresearch.com
7  website: http://www.coasttocoastresearch.com
8 
9  This program is free software: you can redistribute it and/or modify
10  it under the terms of the GNU General Public License as published by
11  the Free Software Foundation, either version 2 of the License, or
12  (at your option) any later version.
13 
14  This program is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  GNU General Public License for more details.
18 
19  You should have received a copy of the GNU General Public License
20  along with this program. If not, see
21  <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>
22  or write to the Free Software Foundation, Inc.,
23  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24 *******************************************************************************/
31 #include "Apg.h"
32 #include "Private.h"
33 
35 #define MEM_ID_ALLOC 0
36 #define MEM_ID_REALLOC 1
37 #define MEM_ID_FREE 2
38 
39 static void vMemStats(APG_MEM_STATS* spStats, apg_uint uiID, APG_MEM_CELL* spIn, APG_MEM_CELL* spOut);
40 static void vActivePush(APG_MEM_CTX* spCtx, APG_MEM_CELL* spCellIn);
41 static void vActivePop(APG_MEM_CTX* spCtx, APG_MEM_CELL* spCellIn);
42 
44 // MEMORY MANAGEMENT COMPONENT FUNCTIONS
45 // - Lowest-level APG component
46 // - Does NO error reporting other than returning a NULL pointer
47 // as an allocation failure indicator.
48 // - always collects memory statistics in both debug and release modes
50 
56 void* vpMemCtorA(PFN_ALLOCATOR pfnAllocator, PFN_DEALLOCATOR pfnDeAllocator){
57  void* vpReturn = NULL;
58  APG_MEM_CTX* spCtx;
59  if(pfnAllocator && pfnDeAllocator){
60  spCtx = (APG_MEM_CTX*)pfnAllocator(sizeof(APG_MEM_CTX));
61  if(spCtx){
62  memset((void*)spCtx, 0, sizeof(APG_MEM_CTX));
63  spCtx->pfnAllocator = pfnAllocator;
64  spCtx->pfnDeAllocator = pfnDeAllocator;
65 
66  // success
67  spCtx->vpValidate = (void*)spCtx;
68  vpReturn = (void*)spCtx;
69  }
70  }
71  return vpReturn;
72 }
73 
77 void* vpMemCtor(){return vpMemCtorA(malloc, free);}
78 
80 // DESCRIPTION: memory component destructor
81 //
82 // FUNCTION: void vMemDtor
83 //
84 // ARG: 1) void* vpCtx
85 // : pointer to a memory context previously returned
86 // from vpMemCtor() or vpMemCtorA()
87 // NULL pointers are ignored, no action and no error
88 //
89 // RETURN: void
90 //
92 
97 void vMemDtor(void* vpCtx){
98  if(vpCtx){
99  APG_MEM_CTX* spCtx = (APG_MEM_CTX*)vpCtx;
100  if(spCtx->vpValidate == (void*)spCtx){
101  PFN_DEALLOCATOR pfnDeAllocator = spCtx->pfnDeAllocator;
102  vMemClear(vpCtx);
103  memset(vpCtx, 0, sizeof(APG_MEM_CTX));
104  pfnDeAllocator(vpCtx);
105  }
106  }
107 }
108 
115 apg_uint uiMemValidate(void* vpCtx){
116  apg_uint uiRet = APG_FALSE;
117  APG_MEM_CTX* spCtx = (APG_MEM_CTX*)vpCtx;
118  if(vpCtx && spCtx->vpValidate == vpCtx){uiRet = APG_TRUE;}
119  return uiRet;
120 }
121 
130 void* vpMemAlloc(void* vpCtx, apg_uint uiBytes){
131  void* vpReturn = NULL;
132  APG_MEM_CTX* spCtx = (APG_MEM_CTX*)vpCtx;
133  APG_MEM_CELL* spCell;
134  if(spCtx && spCtx->vpValidate == (void*)spCtx){
135  spCell = (APG_MEM_CELL*)spCtx->pfnAllocator(uiBytes + sizeof(APG_MEM_CELL));
136  if(spCell){
137  spCell->uiSize = uiBytes;
138 
139  // push it on the active list
140  vActivePush(spCtx, spCell);
141  vMemStats(&spCtx->sStats, MEM_ID_ALLOC, spCell, 0);
142 
143  // success
144  vpReturn = (void*)(spCell + 1);
145  }
146  }
147  return vpReturn;
148 }
149 
157 void vMemFree(void* vpCtx, void* vpData){
158  APG_MEM_CTX* spCtx = (APG_MEM_CTX*)vpCtx;
159  APG_MEM_CELL* spCell;
160  if(vpData){
161  if(spCtx && spCtx->vpValidate == (void*)spCtx){
162  spCell = (APG_MEM_CELL*)vpData;
163  --spCell;
164 
165  // pop from active list
166  vMemStats(&spCtx->sStats, MEM_ID_FREE, spCell, 0);
167  vActivePop(spCtx, spCell);
168  }
169  }
170 }
171 
182 void* vpMemRealloc(void* vpCtx, void* vpData, apg_uint uiBytes){
183  void* vpReturn = NULL;
184  APG_MEM_CTX* spCtx = (APG_MEM_CTX*)vpCtx;
185  APG_MEM_CELL* spOldCell;
186  APG_MEM_CELL* spNewCell;
187  void* vpDst;
188  void* vpSrc;
189  apg_uint uiCopy;
190 
191  if(vpData && uiBytes){
192  if(spCtx && spCtx->vpValidate == (void*)spCtx){
193  spOldCell = (APG_MEM_CELL*)vpData;
194  --spOldCell;
195 
196  // get the new allocation
197  spNewCell = (APG_MEM_CELL*)spCtx->pfnAllocator(uiBytes + sizeof(APG_MEM_CELL));
198  if(spNewCell){
199  spNewCell->spNext = spOldCell->spNext;
200  spNewCell->spPrev = spOldCell->spPrev;
201  spOldCell->spNext->spPrev = (struct APG_MEM_CELL_STRUCT*)spNewCell;
202  spOldCell->spPrev->spNext = (struct APG_MEM_CELL_STRUCT*)spNewCell;
203  spNewCell->uiSeq = spOldCell->uiSeq;
204  spNewCell->uiSize = uiBytes;
205 
206  // copy the data from old allocation to new
207  uiCopy = min(uiBytes, spOldCell->uiSize);
208  vpDst = (void*)(spNewCell + 1);
209  vpSrc = (void*)(spOldCell + 1);
210  memcpy(vpDst, vpSrc, uiCopy);
211 
212  // free the old data
213  vMemStats(&spCtx->sStats, MEM_ID_REALLOC, spOldCell, spNewCell);
214  //APG_MEMSTATS(&spCtx->sStats, MEM_ID_REALLOC, spOldCell, spNewCell);
215  spCtx->pfnDeAllocator((void*)spOldCell);
216  vpReturn = (void*)(spNewCell + 1);
217  }
218  }
219  }
220  return vpReturn;
221 }
222 
231  APG_MEM_CTX* spCtx = (APG_MEM_CTX*)vpCtx;
232  APG_MEM_CELL* spLast;
233  apg_uint uiChk = 0;
234  if(spCtx && spCtx->vpValidate == (void*)spCtx){
235  if(spCtx->spActiveList){
236  spLast = (APG_MEM_CELL*)spCtx->spActiveList->spPrev;
237  uiChk = spLast->uiSeq + 1;
238  }
239  }
240  return uiChk;
241 }
242 
250 void vMemFreeToCheckPoint(void* vpCtx, apg_uint uiChk){
251  APG_MEM_CTX* spCtx = (APG_MEM_CTX*)vpCtx;
252  APG_MEM_CELL* spLast;
253  if(spCtx && spCtx->vpValidate == (void*)spCtx){
254  // release all active blocks above the check point
255  while(APG_TRUE){
256  // break if list is empty
257  if(spCtx->spActiveList == NULL){break;}
258 
259  // remove the last cell from the active list
260  spLast = (APG_MEM_CELL*)spCtx->spActiveList->spPrev;
261 
262  // break if this cell is below check point
263  if(spLast->uiSeq < uiChk){break;}
264 
265  // remove the cell from the active list
266  vMemStats(&spCtx->sStats, MEM_ID_FREE, spLast, 0);
267  vActivePop(spCtx, spLast);
268  }
269  }
270 }
271 
277 void vMemClear(void* vpCtx){vMemFreeToCheckPoint(vpCtx, 0);}
278 
287 apg_uint uiMemStats(void* vpCtx, APG_MEM_STATS* spStats){
288  apg_uint uiRet = 0;
289  APG_MEM_CTX* spMemCtx = (APG_MEM_CTX*)vpCtx;
290  if(vpCtx && uiMemValidate(vpCtx)){
291  if(spStats){
292  memcpy((void*)spStats, (void*)&spMemCtx->sStats, sizeof(APG_MEM_STATS));
293  }
294  uiRet = sizeof(APG_MEM_STATS);
295  }
296  return uiRet;
297 }
298 
300 // STATIC HELPER FUNCTIONS
303 // DESCRIPTION: Updates memory statistics.
304 //
305 // FUNCTION: static void vMemStats
306 //
307 // ARG: 1) APG_MEM_STATS* spStats
308 // : pointer to a statistics struct
309 //
310 // ARG: 2) apg_uint uiID
311 // : MEM_ID_ALLOC - update allocation stats on allocation
312 // : MEM_ID_REALLOC - update reallocation stats
313 // : MEM_ID_FREE - update allocation stats on deallocation
314 //
315 // ARG: 3) APG_MEM_CELL* spIn
316 // : pointer to the memory cell being re/de/allocated
317 //
318 // ARG: 4) APG_MEM_CELL* spOut
319 // : pointer to the new, reallocated memory cell
320 //
321 // RETURN: void
322 //
324 static void vMemStats(APG_MEM_STATS* spStats, apg_uint uiID, APG_MEM_CELL* spIn, APG_MEM_CELL* spOut){
325  switch(uiID) {
326  case MEM_ID_ALLOC:
327  ++spStats->uiAllocations;
328  ++spStats->uiCells;
329  spStats->uiHeapBytes += spIn->uiSize + sizeof(APG_MEM_CELL);
330  if(spStats->uiCells > spStats->uiMaxCells)
331  {
332  spStats->uiMaxCells = spStats->uiCells;
333  }
334  if(spStats->uiHeapBytes > spStats->uiMaxHeapBytes)
335  {
336  spStats->uiMaxHeapBytes = spStats->uiHeapBytes;
337  }
338  break;
339  case MEM_ID_REALLOC:
340  ++spStats->uiReAllocations;
341  spStats->uiHeapBytes += spOut->uiSize - spIn->uiSize;
342  if(spStats->uiHeapBytes > spStats->uiMaxHeapBytes){spStats->uiMaxHeapBytes = spStats->uiHeapBytes;}
343  break;
344  case MEM_ID_FREE:
345  ++spStats->uiFrees;
346  --spStats->uiCells;
347  spStats->uiHeapBytes -= spIn->uiSize + sizeof(APG_MEM_CELL);
348  break;
349  }
350 
351 }
352 
354 // DESCRIPTION: push a new memory cell on the linked list
355 //
356 // FUNCTION: static void vActivePush
357 //
358 // ARG: 1) APG_MEM_CTX* spCtx
359 // : pointer to a memory context previously returned
360 // from vpMemCtor() or vpMemCtorA()
361 //
362 // ARG: 2) APG_MEM_CELL* spCellIn
363 // : the new cell to be pushed
364 //
365 // RETURN: void
366 //
368 static void vActivePush(APG_MEM_CTX* spCtx, APG_MEM_CELL* spCellIn){
369  struct APG_MEM_CELL_STRUCT* spLast;
370  struct APG_MEM_CELL_STRUCT* spFirst;
371  struct APG_MEM_CELL_STRUCT* spCell = (struct APG_MEM_CELL_STRUCT*)spCellIn;
372 
373  // sequence number roll over is a fatal error
374  // link the cell
375  switch(spCtx->uiActiveCellCount){
376  case 0:
377  spCtx->spActiveList = spCell;
378  spCell->spNext = spCell->spPrev = spCell;
379  spCell->uiSeq = 0;
380  break;
381  case 1:
382  spLast = spCtx->spActiveList;
383  spLast->spNext = spLast->spPrev = spCell;
384  spCell->spNext = spCell->spPrev = spLast;
385  spCell->uiSeq = spLast->uiSeq + 1;
386  break;
387  default:
388  spFirst = spCtx->spActiveList;
389  spLast = spFirst->spPrev;
390  spFirst->spPrev = spCell;
391  spLast->spNext = spCell;
392  spCell->spNext = spFirst;
393  spCell->spPrev = spLast;
394  spCell->uiSeq = spLast->uiSeq + 1;
395  break;
396  }
397 
398  ++spCtx->uiActiveCellCount;
399 }
400 
402 // DESCRIPTION: removes (pops) a memory cell from the linked list
403 //
404 // FUNCTION: static void vActivePop
405 //
406 // ARG: 1) APG_MEM_CTX* spCtx
407 // : pointer to a memory context previously returned
408 // from vpMemCtor() or vpMemCtorA()
409 //
410 // ARG: 2) APG_MEM_CELL* spCellIn
411 // : the memory cell to be removed (popped)
412 //
413 // RETURN: void
414 //
416 static void vActivePop(APG_MEM_CTX* spCtx, APG_MEM_CELL* spCellIn){
417  struct APG_MEM_CELL_STRUCT* spPrev;
418  struct APG_MEM_CELL_STRUCT* spNext;
419  struct APG_MEM_CELL_STRUCT* spCell = (struct APG_MEM_CELL_STRUCT*)spCellIn;
420 
421  if(spCtx->spActiveList == spCell){
422  // update the pointer to the first cell
423  if(spCtx->uiActiveCellCount == 1){
424  spCtx->spActiveList = NULL;
425  } else{spCtx->spActiveList = spCtx->spActiveList->spNext;}
426  }
427 
428  // remove the cell from the active list
429  spPrev = spCell->spPrev;
430  spNext = spCell->spNext;
431  spPrev->spNext = spCell->spNext;
432  spNext->spPrev = spCell->spPrev;
433 
434  --spCtx->uiActiveCellCount;
435 
436  // free the data
437  spCtx->pfnDeAllocator((void*)spCell);
438 }
APG_MEM_STATS
generated by the Memory component, available to the user for display of memory statistics
Definition: Apg.h:360
PFN_ALLOCATOR
void *(* PFN_ALLOCATOR)(size_t)
Definition: Apg.h:371
APG_MEM_STATS::uiFrees
apg_uint uiFrees
Definition: Apg.h:363
APG_MEM_STATS::uiMaxCells
apg_uint uiMaxCells
Definition: Apg.h:365
apg_uint
unsigned int apg_uint
Definition: Apg.h:169
PFN_DEALLOCATOR
void(* PFN_DEALLOCATOR)(void *)
Definition: Apg.h:373
APG_MEM_STATS::uiAllocations
apg_uint uiAllocations
Definition: Apg.h:361
uiMemCheckPoint
apg_uint uiMemCheckPoint(void *vpCtx)
Definition: Memory.c:230
vMemDtor
void vMemDtor(void *vpCtx)
Definition: Memory.c:97
uiMemStats
apg_uint uiMemStats(void *vpCtx, APG_MEM_STATS *spStats)
Definition: Memory.c:287
vMemClear
void vMemClear(void *vpCtx)
Definition: Memory.c:277
APG_MEM_STATS::uiCells
apg_uint uiCells
Definition: Apg.h:364
Apg.h
Required header file for all APG-generated parsers. Contains important configuration macros and decla...
vpMemRealloc
void * vpMemRealloc(void *vpCtx, void *vpData, apg_uint uiBytes)
Definition: Memory.c:182
APG_TRUE
#define APG_TRUE
Definition: Apg.h:187
APG_MEM_STATS::uiMaxHeapBytes
apg_uint uiMaxHeapBytes
Definition: Apg.h:367
APG_MEM_STATS::uiReAllocations
apg_uint uiReAllocations
Definition: Apg.h:362
vMemFree
void vMemFree(void *vpCtx, void *vpData)
Definition: Memory.c:157
vpMemCtor
void * vpMemCtor()
Definition: Memory.c:77
min
#define min(a, b)
Definition: Apg.h:296
uiMemValidate
apg_uint uiMemValidate(void *vpCtx)
Definition: Memory.c:115
APG_FALSE
#define APG_FALSE
Definition: Apg.h:190
vpMemCtorA
void * vpMemCtorA(PFN_ALLOCATOR pfnAllocator, PFN_DEALLOCATOR pfnDeAllocator)
Definition: Memory.c:56
vpMemAlloc
void * vpMemAlloc(void *vpCtx, apg_uint uiBytes)
Definition: Memory.c:130
APG_MEM_STATS::uiHeapBytes
apg_uint uiHeapBytes
Definition: Apg.h:366
vMemFreeToCheckPoint
void vMemFreeToCheckPoint(void *vpCtx, apg_uint uiChk)
Definition: Memory.c:250
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/licenses.html or write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.