2 * Copyright (c) 2010 The WebM project authors. All Rights Reserved.
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
16 Stores a list of addreses, their size, and file and line they came from.
17 All exposed lib functions are prefaced by vpx_ and allow the global list
19 Current supported platforms are:
20 Linux, Win32, win_ce and vx_works
21 Further support can be added by defining the platform specific mutex
22 in the memory_tracker struct as well as calls to create/destroy/lock/unlock
23 the mutex in vpx_memory_tracker_init/Destroy and memory_tracker_lock_mutex/unlock_mutex
25 #include "vpx_ports/config.h"
27 #if defined(__uClinux__)
33 #elif defined(WIN32) || defined(_WIN32_WCE)
34 # define WIN32_LEAN_AND_MEAN
37 #elif defined(VXWORKS)
39 #elif defined(NDS_NITRO)
41 # include <nitro/os.h>
46 #include <string.h> //VXWORKS doesn't have a malloc/memory.h file,
47 //this should pull in malloc,free,etc.
50 #include "include/vpx_mem_tracker.h"
52 #undef vpx_malloc //undefine any vpx_mem macros that may affect calls to
53 #undef vpx_free //memory functions in this file
58 #ifndef USE_GLOBAL_FUNCTION_POINTERS
59 # define USE_GLOBAL_FUNCTION_POINTERS 0 //use function pointers instead of compiled functions.
62 #if USE_GLOBAL_FUNCTION_POINTERS
63 static mem_track_malloc_func g_malloc
= malloc
;
64 static mem_track_calloc_func g_calloc
= calloc
;
65 static mem_track_realloc_func g_realloc
= realloc
;
66 static mem_track_free_func g_free
= free
;
67 static mem_track_memcpy_func g_memcpy
= memcpy
;
68 static mem_track_memset_func g_memset
= memset
;
69 static mem_track_memmove_func g_memmove
= memmove
;
70 # define MEM_TRACK_MALLOC g_malloc
71 # define MEM_TRACK_FREE g_free
72 # define MEM_TRACK_MEMCPY g_memcpy
73 # define MEM_TRACK_MEMSET g_memset
75 # define MEM_TRACK_MALLOC vpx_malloc
76 # define MEM_TRACK_FREE vpx_free
77 # define MEM_TRACK_MEMCPY vpx_memcpy
78 # define MEM_TRACK_MEMSET vpx_memset
79 #endif // USE_GLOBAL_FUNCTION_POINTERS
81 /* prototypes for internal library functions */
82 static void memtrack_log(const char *fmt
, ...);
83 static void memory_tracker_dump();
84 static void memory_tracker_check_integrity(char *file
, unsigned int line
);
85 static void memory_tracker_add(size_t addr
, unsigned int size
,
86 char *file
, unsigned int line
,
88 static int memory_tracker_remove(size_t addr
);
89 static struct mem_block
*memory_tracker_find(size_t addr
);
92 # define memory_tracker_lock_mutex() (!g_b_mem_tracker_inited)
93 # define memory_tracker_unlock_mutex()
95 static int memory_tracker_lock_mutex();
96 static int memory_tracker_unlock_mutex();
99 #ifndef VPX_NO_GLOBALS
100 struct memory_tracker
102 struct mem_block
*head
,
106 unsigned int current_allocated
,
110 pthread_mutex_t mutex
;
111 #elif defined(WIN32) || defined(_WIN32_WCE)
113 #elif defined(VXWORKS)
115 #elif defined(NDS_NITRO)
117 #elif defined(NO_MUTEX)
119 #error "No mutex type defined for this platform!"
126 static struct memory_tracker memtrack
; //our global memory allocation list
127 static int g_b_mem_tracker_inited
= 0; //indicates whether the global list has
128 //been initialized (1:yes/0:no)
133 void (*func
)(void *userdata
, const char *fmt
, va_list args
);
135 } g_logging
= {NULL
, 0, NULL
, NULL
};
137 # include "vpx_global_handling.h"
138 #define g_b_mem_tracker_inited vpxglobalm(vpxmem,g_b_mem_tracker_inited)
139 #define g_logging vpxglobalm(vpxmem,g_logging)
140 #define memtrack vpxglobalm(vpxmem,memtrack)
141 #endif // #ifndef VPX_NO_GLOBALS
143 extern void *vpx_malloc(size_t size
);
144 extern void vpx_free(void *memblk
);
145 extern void *vpx_memcpy(void *dest
, const void *src
, size_t length
);
146 extern void *vpx_memset(void *dest
, int val
, size_t length
);
150 * Exposed library functions
155 vpx_memory_tracker_init(int padding_size, int pad_value)
156 padding_size - the size of the padding before and after each mem addr.
157 Values > 0 indicate that integrity checks can be performed
158 by inspecting these areas.
159 pad_value - the initial value within the padding area before and after
162 Initializes global memory tracker structure
163 Allocates the head of the list
165 int vpx_memory_tracker_init(int padding_size
, int pad_value
)
167 if (!g_b_mem_tracker_inited
)
169 if ((memtrack
.head
= (struct mem_block
*)
170 MEM_TRACK_MALLOC(sizeof(struct mem_block
))))
174 MEM_TRACK_MEMSET(memtrack
.head
, 0, sizeof(struct mem_block
));
176 memtrack
.tail
= memtrack
.head
;
178 memtrack
.current_allocated
= 0;
179 memtrack
.max_allocated
= 0;
181 memtrack
.padding_size
= padding_size
;
182 memtrack
.pad_value
= pad_value
;
185 ret
= pthread_mutex_init(&memtrack
.mutex
,
186 NULL
); /*mutex attributes (NULL=default)*/
187 #elif defined(WIN32) || defined(_WIN32_WCE)
188 memtrack
.mutex
= CreateMutex(NULL
, /*security attributes*/
189 FALSE
, /*we don't want initial ownership*/
190 NULL
); /*mutex name*/
191 ret
= !memtrack
.mutex
;
192 #elif defined(VXWORKS)
193 memtrack
.mutex
= sem_bcreate(SEM_Q_FIFO
, /*SEM_Q_FIFO non-priority based mutex*/
194 SEM_FULL
); /*SEM_FULL initial state is unlocked*/
195 ret
= !memtrack
.mutex
;
196 #elif defined(NDS_NITRO)
197 os_init_mutex(&memtrack
.mutex
);
199 #elif defined(NO_MUTEX)
205 memtrack_log("vpx_memory_tracker_init: Error creating mutex!\n");
207 MEM_TRACK_FREE(memtrack
.head
);
208 memtrack
.head
= NULL
;
212 memtrack_log("Memory Tracker init'd, v."vpx_mem_tracker_version
" pad_size:%d pad_val:0x%x %d\n"
216 g_b_mem_tracker_inited
= 1;
221 return g_b_mem_tracker_inited
;
225 vpx_memory_tracker_destroy()
226 If our global struct was initialized zeros out all its members,
227 frees memory and destroys it's mutex
229 void vpx_memory_tracker_destroy()
231 if (!memory_tracker_lock_mutex())
233 struct mem_block
*p
= memtrack
.head
,
234 * p2
= memtrack
.head
;
236 memory_tracker_dump();
246 memtrack
.head
= NULL
;
247 memtrack
.tail
= NULL
;
249 memtrack
.current_allocated
= 0;
250 memtrack
.max_allocated
= 0;
252 if (!g_logging
.type
&& g_logging
.file
&& g_logging
.file
!= stderr
)
254 #if !defined(NDS_NITRO)
255 fclose(g_logging
.file
);
257 g_logging
.file
= NULL
;
260 memory_tracker_unlock_mutex();
262 g_b_mem_tracker_inited
= 0;
267 vpx_memory_tracker_add(size_t addr, unsigned int size,
268 char * file, unsigned int line)
269 addr - memory address to be added to list
271 file - the file addr was referenced from
272 line - the line in file addr was referenced from
273 Adds memory address addr, it's size, file and line it came from
274 to the global list via the thread safe internal library function
276 void vpx_memory_tracker_add(size_t addr
, unsigned int size
,
277 char *file
, unsigned int line
,
280 memory_tracker_add(addr
, size
, file
, line
, padded
);
284 vpx_memory_tracker_remove(size_t addr)
285 addr - memory address to be removed from list
286 Removes addr from the global list via the thread safe
287 internal remove function
289 Same as described for memory_tracker_remove
291 int vpx_memory_tracker_remove(size_t addr
)
293 return memory_tracker_remove(addr
);
297 vpx_memory_tracker_find(size_t addr)
298 addr - address to be found in list
300 If found, pointer to the memory block that matches addr
303 struct mem_block
*vpx_memory_tracker_find(size_t addr
)
305 struct mem_block
*p
= NULL
;
307 if (!memory_tracker_lock_mutex())
309 p
= memory_tracker_find(addr
);
310 memory_tracker_unlock_mutex();
317 vpx_memory_tracker_dump()
318 Locks the memory tracker's mutex and calls the internal
319 library function to dump the current contents of the
320 global memory allocation list
322 void vpx_memory_tracker_dump()
324 if (!memory_tracker_lock_mutex())
326 memory_tracker_dump();
327 memory_tracker_unlock_mutex();
332 vpx_memory_tracker_check_integrity(char* file, unsigned int line)
333 file - The file name where the check was placed
334 line - The line in file where the check was placed
335 Locks the memory tracker's mutex and calls the internal
336 integrity check function to inspect every address in the global
337 memory allocation list
339 void vpx_memory_tracker_check_integrity(char *file
, unsigned int line
)
341 if (!memory_tracker_lock_mutex())
343 memory_tracker_check_integrity(file
, line
);
344 memory_tracker_unlock_mutex();
349 vpx_memory_tracker_set_log_type
350 Sets the logging type for the memory tracker. Based on the value it will
351 direct its output to the appropriate place.
354 -1: if the logging type could not be set, because the value was invalid
355 or because a file could not be opened
357 int vpx_memory_tracker_set_log_type(int type
, char *option
)
368 g_logging
.file
= stderr
;
372 #if !defined(NDS_NITRO)
375 if ((g_logging
.file
= fopen((char *)option
, "w")))
381 #if defined(WIN32) && !defined(_WIN32_WCE)
383 g_logging
.type
= type
;
391 //output the version to the new logging destination
393 memtrack_log("Memory Tracker logging initialized, "
394 "Memory Tracker v."vpx_mem_tracker_version
"\n");
400 vpx_memory_tracker_set_log_func
401 Sets a logging function to be used by the memory tracker.
404 -1: if the logging type could not be set because logfunc was NULL
406 int vpx_memory_tracker_set_log_func(void *userdata
,
407 void(*logfunc
)(void *userdata
,
408 const char *fmt
, va_list args
))
415 g_logging
.userdata
= userdata
;
416 g_logging
.func
= logfunc
;
420 //output the version to the new logging destination
422 memtrack_log("Memory Tracker logging initialized, "
423 "Memory Tracker v."vpx_mem_tracker_version
"\n");
430 * END - Exposed library functions
437 * Internal library functions
441 static void memtrack_log(const char *fmt
, ...)
447 switch (g_logging
.type
)
452 g_logging
.func(g_logging
.userdata
, fmt
, list
);
459 vfprintf(g_logging
.file
, fmt
, list
);
460 fflush(g_logging
.file
);
464 #if defined(WIN32) && !defined(_WIN32_WCE)
468 _vsnprintf(temp
, sizeof(temp
) / sizeof(char) - 1, fmt
, list
);
469 OutputDebugString(temp
);
481 memory_tracker_dump()
482 Dumps the current contents of the global memory allocation list
484 static void memory_tracker_dump()
487 struct mem_block
*p
= (memtrack
.head
? memtrack
.head
->next
: NULL
);
489 memtrack_log("\n_currently Allocated= %d; Max allocated= %d\n",
490 memtrack
.current_allocated
, memtrack
.max_allocated
);
494 #if defined(WIN32) && !defined(_WIN32_WCE)
496 /*when using outputdebugstring, output filenames so they
497 can be clicked to be opened in visual studio*/
498 if (g_logging
.type
== 1)
499 memtrack_log("memblocks[%d].addr= 0x%.8x, memblocks[%d].size= %d, file:\n"
505 memtrack_log("memblocks[%d].addr= 0x%.8x, memblocks[%d].size= %d, file: %s, line: %d\n", i
,
511 if (!(i
% 20)) os_sleep(500);
523 memory_tracker_check_integrity(char* file, unsigned int file)
524 file - the file name where the check was placed
525 line - the line in file where the check was placed
526 If a padding_size was supplied to vpx_memory_tracker_init()
527 this function will check ea. addr in the list verifying that
528 addr-padding_size and addr+padding_size is filled with pad_value
530 static void memory_tracker_check_integrity(char *file
, unsigned int line
)
532 if (memtrack
.padding_size
)
536 unsigned char *p_show_me
,
538 unsigned int tempme
= memtrack
.pad_value
,
541 unsigned char *x_bounds
;
542 struct mem_block
*p
= memtrack
.head
->next
;
546 //x_bounds = (unsigned char*)p->addr;
547 //back up VPX_BYTE_ALIGNMENT
548 //x_bounds -= memtrack.padding_size;
550 if (p
->padded
) // can the bounds be checked?
552 /*yes, move to the address that was actually allocated
554 x_bounds
= (unsigned char *)(((size_t *)p
->addr
)[-1]);
556 for (i
= 0; i
< memtrack
.padding_size
; i
+= sizeof(unsigned int))
558 p_show_me
= (x_bounds
+ i
);
559 p_show_me2
= (unsigned char *)(p
->addr
+ p
->size
+ i
);
561 MEM_TRACK_MEMCPY(&dead1
, p_show_me
, sizeof(unsigned int));
562 MEM_TRACK_MEMCPY(&dead2
, p_show_me2
, sizeof(unsigned int));
564 if ((dead1
!= tempme
) || (dead2
!= tempme
))
566 memtrack_log("\n[vpx_mem integrity check failed]:\n"
567 " index[%d,%d] {%s:%d} addr=0x%x, size=%d,"
568 " file: %s, line: %d c0:0x%x c1:0x%x\n",
569 index
, i
, file
, line
, p
->addr
, p
->size
, p
->file
,
570 p
->line
, dead1
, dead2
);
582 memory_tracker_add(size_t addr, unsigned int size,
583 char * file, unsigned int line)
584 Adds an address (addr), it's size, file and line number to our list.
585 Adjusts the total bytes allocated and max bytes allocated if necessary.
586 If memory cannot be allocated the list will be destroyed.
588 void memory_tracker_add(size_t addr
, unsigned int size
,
589 char *file
, unsigned int line
,
592 if (!memory_tracker_lock_mutex())
596 p
= MEM_TRACK_MALLOC(sizeof(struct mem_block
));
600 p
->prev
= memtrack
.tail
;
611 memtrack
.current_allocated
+= size
;
613 if (memtrack
.current_allocated
> memtrack
.max_allocated
)
614 memtrack
.max_allocated
= memtrack
.current_allocated
;
616 //memtrack_log("memory_tracker_add: added addr=0x%.8x\n", addr);
618 memory_tracker_unlock_mutex();
622 memtrack_log("memory_tracker_add: error allocating memory!\n");
623 memory_tracker_unlock_mutex();
624 vpx_memory_tracker_destroy();
630 memory_tracker_remove(size_t addr)
631 Removes an address and its corresponding size (if they exist)
632 from the memory tracker list and adjusts the current number
636 -1: if the mutex could not be locked
637 -2: if the addr was not found in the list
639 int memory_tracker_remove(size_t addr
)
643 if (!memory_tracker_lock_mutex())
647 if ((p
= memory_tracker_find(addr
)))
649 memtrack
.current_allocated
-= p
->size
;
651 p
->prev
->next
= p
->next
;
654 p
->next
->prev
= p
->prev
;
656 memtrack
.tail
= p
->prev
;
664 memtrack_log("memory_tracker_remove(): addr not found in list,"
670 memory_tracker_unlock_mutex();
677 memory_tracker_find(size_t addr)
678 Finds an address in our addrs list
679 NOTE: the mutex MUST be locked in the other internal
680 functions before calling this one. This avoids
681 the need for repeated locking and unlocking as in Remove
682 Returns: pointer to the mem block if found, NULL otherwise
684 static struct mem_block
*memory_tracker_find(size_t addr
)
686 struct mem_block
*p
= NULL
;
690 p
= memtrack
.head
->next
;
692 while (p
&& (p
->addr
!= addr
))
700 #if !defined(NO_MUTEX)
702 memory_tracker_lock_mutex()
703 Locks the memory tracker mutex with a platform specific call
706 <0: Failure, either the mutex was not initialized
707 or the call to lock the mutex failed
709 static int memory_tracker_lock_mutex()
713 if (g_b_mem_tracker_inited
)
717 ret
= pthread_mutex_lock(&memtrack
.mutex
);
718 #elif defined(WIN32) || defined(_WIN32_WCE)
719 ret
= WaitForSingleObject(memtrack
.mutex
, INFINITE
);
720 #elif defined(VXWORKS)
721 ret
= sem_take(memtrack
.mutex
, WAIT_FOREVER
);
722 #elif defined(NDS_NITRO)
723 os_lock_mutex(&memtrack
.mutex
);
729 memtrack_log("memory_tracker_lock_mutex: mutex lock failed\n");
737 memory_tracker_unlock_mutex()
738 Unlocks the memory tracker mutex with a platform specific call
741 <0: Failure, either the mutex was not initialized
742 or the call to unlock the mutex failed
744 static int memory_tracker_unlock_mutex()
748 if (g_b_mem_tracker_inited
)
752 ret
= pthread_mutex_unlock(&memtrack
.mutex
);
753 #elif defined(WIN32) || defined(_WIN32_WCE)
754 ret
= !ReleaseMutex(memtrack
.mutex
);
755 #elif defined(VXWORKS)
756 ret
= sem_give(memtrack
.mutex
);
757 #elif defined(NDS_NITRO)
758 os_unlock_mutex(&memtrack
.mutex
);
764 memtrack_log("memory_tracker_unlock_mutex: mutex unlock failed\n");
773 vpx_memory_tracker_set_functions
775 Sets the function pointers for the standard library functions.
779 -1: if the use global function pointers is not set.
781 int vpx_memory_tracker_set_functions(mem_track_malloc_func g_malloc_l
782 , mem_track_calloc_func g_calloc_l
783 , mem_track_realloc_func g_realloc_l
784 , mem_track_free_func g_free_l
785 , mem_track_memcpy_func g_memcpy_l
786 , mem_track_memset_func g_memset_l
787 , mem_track_memmove_func g_memmove_l
)
789 #if USE_GLOBAL_FUNCTION_POINTERS
792 g_malloc
= g_malloc_l
;
795 g_calloc
= g_calloc_l
;
798 g_realloc
= g_realloc_l
;
804 g_memcpy
= g_memcpy_l
;
807 g_memset
= g_memset_l
;
810 g_memmove
= g_memmove_l
;