pmemory_ext.c revision 4a68b3365c8c50aa93505e99ead2565ab73dcdb0
1/*---------------------------------------------------------------------------*
2 *  pmemory_ext.c  *
3 *                                                                           *
4 *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
5 *                                                                           *
6 *  Licensed under the Apache License, Version 2.0 (the 'License');          *
7 *  you may not use this file except in compliance with the License.         *
8 *                                                                           *
9 *  You may obtain a copy of the License at                                  *
10 *      http://www.apache.org/licenses/LICENSE-2.0                           *
11 *                                                                           *
12 *  Unless required by applicable law or agreed to in writing, software      *
13 *  distributed under the License is distributed on an 'AS IS' BASIS,        *
14 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
15 *  See the License for the specific language governing permissions and      *
16 *  limitations under the License.                                           *
17 *                                                                           *
18 *---------------------------------------------------------------------------*/
19
20
21
22#include "pmemory.h"
23#include "ptrd.h"
24#include "pmutex.h"
25#include "passert.h"
26#include "pmemory_ext.h"
27#include "pmalloc.h"
28
29#ifdef __cplusplus
30extern "C"
31{
32#endif
33
34#if defined(USE_THREAD) && defined(USE_DINKUM_LIB_DIRECT)
35  static MUTEX memextMutex;
36#endif
37
38#ifdef RTXC
39  void* operator new(size_t size)
40  {
41    return (PortNew(size));
42  }
43  void  operator delete(void* ptr)
44  {
45    PortDelete(ptr);
46  }
47#endif
48
49#if defined(PORTABLE_DINKUM_MEM_MGR) || defined(PORTABLE_FIXED_SIZE_MEM_BLOCK_SCHEME)
50
51  /* to assist with leak checking */
52static int portNewCount = 0;
53static int portDeleteCount = 0;
54
55  /* enable writing and checking of guard words if debugging is enabled */
56#ifdef _DEBUG
57  /* crash on Xanavi's board with this option on, do not know why */
58  /* #define DBG_GUARD_WORDS */
59#endif /* _DEBUG */
60
61  /* ************************************************************************************
62   * PORTABLE_PSOS_BLOCK_SCHEME_MEM_MGR || PORTABLE_DINKUM_MEM_MGR || PORTABLE_FIXED_SIZE_MEM_BLOCK_SCHEME
63   * ************************************************************************************/
64
65  /* data ******************************************************************************/
66
67  static BOOL  gMemoryInitted = FALSE; /* TODO: Temporary fix to PortTerm failure */
68
69#define MEM_MGR_GetPoolSize()     PortMallocGetPoolSize()
70#define MEM_MGR_SetPoolSize(sizeInBytes)  PortMallocSetPoolSize(sizeInBytes)
71#define MEM_MGR_Init()       PortMallocInit()
72#define MEM_MGR_Term()              PortMallocTerm()
73#define MEM_MGR_Allocate(sizeInBytes)   PortMalloc(sizeInBytes)
74#define MEM_MGR_Free(objectPtr)     PortFree(objectPtr)
75#define MEM_MGR_Dump()
76#define MEM_MGR_GetMaxMemUsed()     PortMallocGetMaxMemUsed()
77
78  /* guard word data ********************************************************/
79
80#ifdef DBG_GUARD_WORDS
81#define GUARD_BEGIN  0xbbbbbbbb
82#define GUARD_END    0xeeeeeeee
83
84#define GUARD_OFF_REQ_SIZE   0
85#define GUARD_OFF_START    sizeof(unsigned int)
86#define GUARD_OFF_PTR    (sizeof(unsigned int) + sizeof(unsigned int))
87#define GUARD_EXTRA     (sizeof(unsigned int) + sizeof(unsigned int) + sizeof(unsigned int))
88#define GUARD_OFF_END(allocSize)    ((allocSize) - sizeof(unsigned int))
89#define GUARD_ALLOC_SIZE(reqSize)   ((reqSize)+GUARD_EXTRA)
90
91#define GUARD_PTR_FIELD(ptr,off) (unsigned int *)((char *)(ptr) + (off))
92#define GUARD_ALLOC_PTR(ptr)  (void*) ((char *)(ptr) - GUARD_OFF_PTR)
93#endif
94
95  /* scan guard words data **************************************************/
96
97  /* maintain a static list of allocated blocks (didn't want to perform any dynamic allocation).
98   * This list can be scanned by PortMemScan() to determine if any allocated blocks
99   * have overwritten their guard words.
100   * Calling PortDelete() will check guard words upon de-allocation, but many
101   * allocated blocks are only freed at program termination, which sometimes doesn't happen.
102   *
103   * This software is enabled separately with DBG_SCAN_GUARD_WORDS, because the performance
104   * overhead is severe.
105   */
106#ifdef DBG_SCAN_GUARD_WORDS
107#define MAX_ALLOCATED_BLOCKS  80000
108  static void *allocArray[MAX_ALLOCATED_BLOCKS+1];
109  static int allocArrayCount = 0;
110
111  void AddToAllocList(void *memPtr);
112  void RemoveFromAllocList(void *memPtr);
113
114#define ADD_TO_ALLOC_LIST(ptr)   AddToAllocList(ptr)
115#define REMOVE_FROM_ALLOC_LIST(ptr)  RemoveFromAllocList(ptr)
116
117#else
118#define ADD_TO_ALLOC_LIST(ptr)
119#define REMOVE_FROM_ALLOC_LIST(ptr)
120#endif
121
122  /* Guard Functions ********************************************************/
123
124#ifdef DBG_SCAN_GUARD_WORDS
125  /* AddToAllocList() : maintain an array of allocated blocks that can be
126   * used by PortMemScan() to check for overwritten guard words.
127   */
128  void AddToAllocList(void *memPtr)
129  {
130    allocArray[allocArrayCount] = memPtr;
131    allocArrayCount++;
132    if (allocArrayCount >= MAX_ALLOCATED_BLOCKS)
133    {
134      char buf[256];
135      sprintf(buf, "AddToAllocList ERROR : MAX_ALLOCATED_BLOCKS is too small (%d)", allocArrayCount);
136      PORT_INTERNAL_ERROR(buf);
137    }
138  }
139
140  /* RemoveFromAllocList() : maintain an array of allocated blocks that can be
141   * used by PortMemScan() to check for overwritten guard words.
142   */
143  void RemoveFromAllocList(void *memPtr)
144  {
145    int i;               /* loop index */
146    int j;               /* loop index */
147    int inList = FALSE;  /* TRUE when found in list */
148
149    for (i = 0; i < allocArrayCount; i++)
150    {
151      if (allocArray[i] == memPtr)
152      {
153        inList = TRUE;
154        break;
155      }
156    }
157    PORT_ASSERT(inList == TRUE);  /* MUST be in list */
158    /* remove by sliding down all following entries */
159    for (j = i + 1; j < allocArrayCount; j++)
160      allocArray[j-1] = allocArray[j];
161    allocArrayCount--;
162    allocArray[allocArrayCount] = NULL; /* clear out end of list */
163  }
164
165  /* PortMemScan() : scan the array of allocated blocks, confirming that no
166   * allocated block has overwritten its guard words.
167   */
168  void PortMemScan(void)
169  {
170    int          i;
171
172    PortCriticalSectionEnter(&PortMemoryCriticalSection);
173
174    /* scan the allocated memory list */
175    for (i = 0; i < allocArrayCount; i++)
176    {
177      /* verify that guard words have not been corrupted */
178      void   *memPtr   = allocArray[i];
179      void         *allocPtr      = GUARD_ALLOC_PTR(memPtr);
180      unsigned int *requestedSizePtr  = GUARD_PTR_FIELD(allocPtr, GUARD_OFF_REQ_SIZE);
181      unsigned int *guardStartPtr     = GUARD_PTR_FIELD(allocPtr, GUARD_OFF_START);
182      unsigned int *guardEndPtr       = GUARD_PTR_FIELD(allocPtr, GUARD_OFF_END(GUARD_ALLOC_SIZE(*requestedSizePtr)));
183
184      if ((*guardStartPtr) != GUARD_BEGIN)
185      {
186        PLogError("PortMemScan : corrupted start guard from block 0x%08x \n", (int)memPtr);
187      }
188      if ((*guardEndPtr)   != GUARD_END)
189      {
190        PLogError("PortMemScan : corrupted end guard from block 0x%08x \n", (int)memPtr);
191      }
192    }
193
194    PortCriticalSectionLeave(&PortMemoryCriticalSection);
195  }
196#endif /* DBG_SCAN_GUARD_WORDS */
197
198  /* Port Memory Functions ******************************************************/
199
200  /* PortMemGetPoolSize() : return size of portable memory pool, or 0 if
201   * unknown.
202   */
203  int  PortMemGetPoolSize(void)
204  {
205    return MEM_MGR_GetPoolSize();
206  }
207
208  /* PortMemSetPoolSize() : set size of portable memory pool on PSOS.
209   * This must be called before PortMemoryInit(), which is called by PortInit().
210   */
211  void PortMemSetPoolSize(size_t sizeInBytes)
212  {
213    MEM_MGR_SetPoolSize(sizeInBytes);
214  }
215
216  /* PortMemoryInit() :
217   */
218
219  int  PortMemoryInit(void)
220  {
221#if defined(USE_THREAD) && defined(USE_DINKUM_LIB_DIRECT)
222    if (createMutex(&memextMutex) == ESR_SUCCESS)
223#endif
224    {
225      if (!gMemoryInitted)
226      {
227        MEM_MGR_Init();
228        gMemoryInitted = TRUE;
229      }
230    }
231
232    return gMemoryInitted;
233  }
234
235  /* PortMemoryTerm() :
236   */
237
238  void  PortMemoryTerm(void)
239  {
240    /* TODO: MEM_PSOS_BLOCK_SCHEME
241     * Figure out why free memory causes rn#0 is get messed up! */
242    MEM_MGR_Term();
243#if defined(USE_THREAD) && defined(USE_DINKUM_LIB_DIRECT)
244    deleteMutex(&memextMutex);
245#endif
246    gMemoryInitted = FALSE;
247  }
248
249  /* PortNew() :
250   */
251
252  void* PortNew(size_t sizeInBytes)
253  {
254    if (gMemoryInitted)
255    {
256      void *pMemory = NULL;
257
258#if defined(USE_THREAD) && defined(USE_DINKUM_LIB_DIRECT)
259      lockMutex(&memextMutex);
260#endif
261      portNewCount++;
262
263#ifdef DBG_GUARD_WORDS
264      sizeInBytes += GUARD_EXTRA; /* space for: requestedSize,guardStart,guardEnd */
265#endif
266
267      pMemory = MEM_MGR_Allocate(sizeInBytes);
268
269#ifdef DBG_GUARD_WORDS
270      if (NULL != pMemory)
271      {
272        /* at the beginning of the buffer, store the requested size and a guard word.
273         * Store another guard word at the end of the buffer.
274         */
275        /* set guard words at either end of allocated buffer; will be checked at delete time */
276        unsigned int * requestedSizePtr  = GUARD_PTR_FIELD(pMemory, GUARD_OFF_REQ_SIZE);
277        unsigned int * guardStartPtr     = GUARD_PTR_FIELD(pMemory, GUARD_OFF_START);
278        unsigned int * guardEndPtr       = GUARD_PTR_FIELD(pMemory, GUARD_OFF_END(sizeInBytes));
279
280        *requestedSizePtr = sizeInBytes - GUARD_EXTRA;
281        *guardStartPtr    = GUARD_BEGIN;
282        *guardEndPtr      = GUARD_END;
283        pMemory     = (void *) GUARD_PTR_FIELD(pMemory, GUARD_OFF_PTR);
284        ADD_TO_ALLOC_LIST(pMemory);
285      }
286#endif /* DBG_GUARD_WORDS */
287#if defined(USE_THREAD) && defined(USE_DINKUM_LIB_DIRECT)
288      unlockMutex(&memextMutex);
289#endif
290      return pMemory;
291    }
292#ifdef PSOSIM
293    /* PSOSIM's license manager calls new() before PSOS is running */
294    else
295    {
296      return(malloc(sizeInBytes));
297    }
298#else  /* PSOSIM */
299    /* Memory allocator not initialized when request for memory was made */
300    passert(FALSE && "Call PortInit() before calling any portable functions\r\n");
301    return NULL;
302#endif /* PSOSIM */
303  }
304
305  void PortDelete(void* objectPtr)
306  {
307#if defined(USE_THREAD) && defined(USE_DINKUM_LIB_DIRECT)
308    lockMutex(&memextMutex);
309#endif
310    portDeleteCount++;
311
312#ifdef DBG_GUARD_WORDS
313    {
314      /* verify that guard words have not been corrupted */
315      void *allocPtr     = GUARD_ALLOC_PTR(objectPtr);
316      unsigned int *requestedSizePtr  = GUARD_PTR_FIELD(allocPtr, GUARD_OFF_REQ_SIZE);
317      unsigned int *guardStartPtr     = GUARD_PTR_FIELD(allocPtr, GUARD_OFF_START);
318      unsigned int *guardEndPtr       = GUARD_PTR_FIELD(allocPtr, GUARD_OFF_END(GUARD_ALLOC_SIZE(*requestedSizePtr)));
319
320      passert((*guardStartPtr) == GUARD_BEGIN);
321      passert((*guardEndPtr)   == GUARD_END);
322      REMOVE_FROM_ALLOC_LIST(allocPtr);
323      objectPtr = allocPtr;
324    }
325#endif
326
327    MEM_MGR_Free(objectPtr);
328#if defined(USE_THREAD) && defined(USE_DINKUM_LIB_DIRECT)
329    unlockMutex(&memextMutex);
330#endif
331  }
332
333  void PortMemTrackDump(void)
334  {
335    MEM_MGR_Dump();
336  }
337
338  /* PortGetMaxMemUsed() : return the maximum real memory allocated.
339   * There is another function of the same name in pmalloc.c, for tracking
340   * non-psos block memory. It uses #ifndef MEM_PSOS_BLOCK_SCHEME to enable.
341   */
342  int PortGetMaxMemUsed(void)
343  {
344    return MEM_MGR_GetMaxMemUsed();
345  }
346
347  /* PortMemCntReset() : reset the New/Delete count.
348   * This is useful for checking that each new has a corresponding delete once
349   * the system gets into a steady state.
350   */
351  void PortMemCntReset()
352  {
353    portNewCount = 0;
354    portDeleteCount = 0;
355  }
356
357
358  /* PortMemGetCount() : return the accumulated new & delete counts */
359  void PortMemGetCount(int *newCount, int *deleteCount)
360  {
361    *newCount    = portNewCount;
362    *deleteCount = portDeleteCount;
363  }
364
365#endif /* (==PORTABLE_PSOS_BLOCK_SCHEME_MEM_MGR) || (==PORTABLE_DINKUM_MEM_MGR) || (==PORTABLE_FIXED_SIZE_MEM_BLOCK_SCHEME) */
366
367#ifdef __cplusplus
368}
369#endif
370