• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
30 extern "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
new(size_t size)39   void* operator new(size_t size)
40   {
41     return (PortNew(size));
42   }
delete(void * ptr)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 */
52 static int portNewCount = 0;
53 static 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    */
AddToAllocList(void * memPtr)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    */
RemoveFromAllocList(void * memPtr)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    */
PortMemScan(void)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    */
PortMemGetPoolSize(void)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    */
PortMemSetPoolSize(size_t sizeInBytes)211   void PortMemSetPoolSize(size_t sizeInBytes)
212   {
213     MEM_MGR_SetPoolSize(sizeInBytes);
214   }
215 
216   /* PortMemoryInit() :
217    */
218 
PortMemoryInit(void)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 
PortMemoryTerm(void)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 
PortNew(size_t sizeInBytes)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 
PortDelete(void * objectPtr)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 
PortMemTrackDump(void)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    */
PortGetMaxMemUsed(void)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    */
PortMemCntReset()351   void PortMemCntReset()
352   {
353     portNewCount = 0;
354     portDeleteCount = 0;
355   }
356 
357 
358   /* PortMemGetCount() : return the accumulated new & delete counts */
PortMemGetCount(int * newCount,int * deleteCount)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