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_config.h"
27 #if defined(__uClinux__)
33 #elif defined(WIN32) || defined(_WIN32_WCE)
34 # define WIN32_LEAN_AND_MEAN
37 #elif defined(VXWORKS)
43 #include <string.h> // VXWORKS doesn't have a malloc/memory.h file,
44 // this should pull in malloc,free,etc.
47 #include "include/vpx_mem_tracker.h"
49 #undef vpx_malloc // undefine any vpx_mem macros that may affect calls to
50 #undef vpx_free // memory functions in this file
55 #ifndef USE_GLOBAL_FUNCTION_POINTERS
56 # define USE_GLOBAL_FUNCTION_POINTERS 0 // use function pointers instead of compiled functions.
59 #if USE_GLOBAL_FUNCTION_POINTERS
60 static mem_track_malloc_func g_malloc
= malloc
;
61 static mem_track_calloc_func g_calloc
= calloc
;
62 static mem_track_realloc_func g_realloc
= realloc
;
63 static mem_track_free_func g_free
= free
;
64 static mem_track_memcpy_func g_memcpy
= memcpy
;
65 static mem_track_memset_func g_memset
= memset
;
66 static mem_track_memmove_func g_memmove
= memmove
;
67 # define MEM_TRACK_MALLOC g_malloc
68 # define MEM_TRACK_FREE g_free
69 # define MEM_TRACK_MEMCPY g_memcpy
70 # define MEM_TRACK_MEMSET g_memset
72 # define MEM_TRACK_MALLOC vpx_malloc
73 # define MEM_TRACK_FREE vpx_free
74 # define MEM_TRACK_MEMCPY vpx_memcpy
75 # define MEM_TRACK_MEMSET vpx_memset
76 #endif // USE_GLOBAL_FUNCTION_POINTERS
78 /* prototypes for internal library functions */
79 static void memtrack_log(const char *fmt
, ...);
80 static void memory_tracker_dump();
81 static void memory_tracker_check_integrity(char *file
, unsigned int line
);
82 static void memory_tracker_add(size_t addr
, unsigned int size
,
83 char *file
, unsigned int line
,
85 static int memory_tracker_remove(size_t addr
);
86 static struct mem_block
*memory_tracker_find(size_t addr
);
89 # define memory_tracker_lock_mutex() (!g_b_mem_tracker_inited)
90 # define memory_tracker_unlock_mutex()
92 static int memory_tracker_lock_mutex();
93 static int memory_tracker_unlock_mutex();
96 #ifndef VPX_NO_GLOBALS
97 struct memory_tracker
{
98 struct mem_block
*head
,
102 unsigned int current_allocated
,
106 pthread_mutex_t mutex
;
107 #elif defined(WIN32) || defined(_WIN32_WCE)
109 #elif defined(VXWORKS)
111 #elif defined(NO_MUTEX)
113 #error "No mutex type defined for this platform!"
120 static struct memory_tracker memtrack
; // our global memory allocation list
121 static int g_b_mem_tracker_inited
= 0; // indicates whether the global list has
122 // been initialized (1:yes/0:no)
126 void (*func
)(void *userdata
, const char *fmt
, va_list args
);
128 } g_logging
= {NULL
, 0, NULL
, NULL
};
130 # include "vpx_global_handling.h"
131 #define g_b_mem_tracker_inited vpxglobalm(vpxmem,g_b_mem_tracker_inited)
132 #define g_logging vpxglobalm(vpxmem,g_logging)
133 #define memtrack vpxglobalm(vpxmem,memtrack)
134 #endif // #ifndef VPX_NO_GLOBALS
136 extern void *vpx_malloc(size_t size
);
137 extern void vpx_free(void *memblk
);
138 extern void *vpx_memcpy(void *dest
, const void *src
, size_t length
);
139 extern void *vpx_memset(void *dest
, int val
, size_t length
);
143 * Exposed library functions
148 vpx_memory_tracker_init(int padding_size, int pad_value)
149 padding_size - the size of the padding before and after each mem addr.
150 Values > 0 indicate that integrity checks can be performed
151 by inspecting these areas.
152 pad_value - the initial value within the padding area before and after
155 Initializes global memory tracker structure
156 Allocates the head of the list
158 int vpx_memory_tracker_init(int padding_size
, int pad_value
) {
159 if (!g_b_mem_tracker_inited
) {
160 if ((memtrack
.head
= (struct mem_block
*)
161 MEM_TRACK_MALLOC(sizeof(struct mem_block
)))) {
164 MEM_TRACK_MEMSET(memtrack
.head
, 0, sizeof(struct mem_block
));
166 memtrack
.tail
= memtrack
.head
;
168 memtrack
.current_allocated
= 0;
169 memtrack
.max_allocated
= 0;
171 memtrack
.padding_size
= padding_size
;
172 memtrack
.pad_value
= pad_value
;
175 ret
= pthread_mutex_init(&memtrack
.mutex
,
176 NULL
); /*mutex attributes (NULL=default)*/
177 #elif defined(WIN32) || defined(_WIN32_WCE)
178 memtrack
.mutex
= CreateMutex(NULL
, /*security attributes*/
179 FALSE
, /*we don't want initial ownership*/
180 NULL
); /*mutex name*/
181 ret
= !memtrack
.mutex
;
182 #elif defined(VXWORKS)
183 memtrack
.mutex
= sem_bcreate(SEM_Q_FIFO
, /*SEM_Q_FIFO non-priority based mutex*/
184 SEM_FULL
); /*SEM_FULL initial state is unlocked*/
185 ret
= !memtrack
.mutex
;
186 #elif defined(NO_MUTEX)
191 memtrack_log("vpx_memory_tracker_init: Error creating mutex!\n");
193 MEM_TRACK_FREE(memtrack
.head
);
194 memtrack
.head
= NULL
;
196 memtrack_log("Memory Tracker init'd, v."vpx_mem_tracker_version
" pad_size:%d pad_val:0x%x %d\n"
200 g_b_mem_tracker_inited
= 1;
205 return g_b_mem_tracker_inited
;
209 vpx_memory_tracker_destroy()
210 If our global struct was initialized zeros out all its members,
211 frees memory and destroys it's mutex
213 void vpx_memory_tracker_destroy() {
214 if (!memory_tracker_lock_mutex()) {
215 struct mem_block
*p
= memtrack
.head
,
216 * p2
= memtrack
.head
;
218 memory_tracker_dump();
227 memtrack
.head
= NULL
;
228 memtrack
.tail
= NULL
;
230 memtrack
.current_allocated
= 0;
231 memtrack
.max_allocated
= 0;
233 if (!g_logging
.type
&& g_logging
.file
&& g_logging
.file
!= stderr
) {
234 fclose(g_logging
.file
);
235 g_logging
.file
= NULL
;
238 memory_tracker_unlock_mutex();
240 g_b_mem_tracker_inited
= 0;
245 vpx_memory_tracker_add(size_t addr, unsigned int size,
246 char * file, unsigned int line)
247 addr - memory address to be added to list
249 file - the file addr was referenced from
250 line - the line in file addr was referenced from
251 Adds memory address addr, it's size, file and line it came from
252 to the global list via the thread safe internal library function
254 void vpx_memory_tracker_add(size_t addr
, unsigned int size
,
255 char *file
, unsigned int line
,
257 memory_tracker_add(addr
, size
, file
, line
, padded
);
261 vpx_memory_tracker_remove(size_t addr)
262 addr - memory address to be removed from list
263 Removes addr from the global list via the thread safe
264 internal remove function
266 Same as described for memory_tracker_remove
268 int vpx_memory_tracker_remove(size_t addr
) {
269 return memory_tracker_remove(addr
);
273 vpx_memory_tracker_find(size_t addr)
274 addr - address to be found in list
276 If found, pointer to the memory block that matches addr
279 struct mem_block
*vpx_memory_tracker_find(size_t addr
) {
280 struct mem_block
*p
= NULL
;
282 if (!memory_tracker_lock_mutex()) {
283 p
= memory_tracker_find(addr
);
284 memory_tracker_unlock_mutex();
291 vpx_memory_tracker_dump()
292 Locks the memory tracker's mutex and calls the internal
293 library function to dump the current contents of the
294 global memory allocation list
296 void vpx_memory_tracker_dump() {
297 if (!memory_tracker_lock_mutex()) {
298 memory_tracker_dump();
299 memory_tracker_unlock_mutex();
304 vpx_memory_tracker_check_integrity(char* file, unsigned int line)
305 file - The file name where the check was placed
306 line - The line in file where the check was placed
307 Locks the memory tracker's mutex and calls the internal
308 integrity check function to inspect every address in the global
309 memory allocation list
311 void vpx_memory_tracker_check_integrity(char *file
, unsigned int line
) {
312 if (!memory_tracker_lock_mutex()) {
313 memory_tracker_check_integrity(file
, line
);
314 memory_tracker_unlock_mutex();
319 vpx_memory_tracker_set_log_type
320 Sets the logging type for the memory tracker. Based on the value it will
321 direct its output to the appropriate place.
324 -1: if the logging type could not be set, because the value was invalid
325 or because a file could not be opened
327 int vpx_memory_tracker_set_log_type(int type
, char *option
) {
335 g_logging
.file
= stderr
;
338 if ((g_logging
.file
= fopen((char *)option
, "w")))
343 #if defined(WIN32) && !defined(_WIN32_WCE)
345 g_logging
.type
= type
;
353 // output the version to the new logging destination
355 memtrack_log("Memory Tracker logging initialized, "
356 "Memory Tracker v."vpx_mem_tracker_version
"\n");
362 vpx_memory_tracker_set_log_func
363 Sets a logging function to be used by the memory tracker.
366 -1: if the logging type could not be set because logfunc was NULL
368 int vpx_memory_tracker_set_log_func(void *userdata
,
369 void(*logfunc
)(void *userdata
,
370 const char *fmt
, va_list args
)) {
375 g_logging
.userdata
= userdata
;
376 g_logging
.func
= logfunc
;
380 // output the version to the new logging destination
382 memtrack_log("Memory Tracker logging initialized, "
383 "Memory Tracker v."vpx_mem_tracker_version
"\n");
390 * END - Exposed library functions
397 * Internal library functions
401 static void memtrack_log(const char *fmt
, ...) {
406 switch (g_logging
.type
) {
410 g_logging
.func(g_logging
.userdata
, fmt
, list
);
415 if (g_logging
.file
) {
416 vfprintf(g_logging
.file
, fmt
, list
);
417 fflush(g_logging
.file
);
421 #if defined(WIN32) && !defined(_WIN32_WCE)
424 _vsnprintf(temp
, sizeof(temp
) / sizeof(char) - 1, fmt
, list
);
425 OutputDebugString(temp
);
437 memory_tracker_dump()
438 Dumps the current contents of the global memory allocation list
440 static void memory_tracker_dump() {
442 struct mem_block
*p
= (memtrack
.head
? memtrack
.head
->next
: NULL
);
444 memtrack_log("\n_currently Allocated= %d; Max allocated= %d\n",
445 memtrack
.current_allocated
, memtrack
.max_allocated
);
448 #if defined(WIN32) && !defined(_WIN32_WCE)
450 /*when using outputdebugstring, output filenames so they
451 can be clicked to be opened in visual studio*/
452 if (g_logging
.type
== 1)
453 memtrack_log("memblocks[%d].addr= 0x%.8x, memblocks[%d].size= %d, file:\n"
459 memtrack_log("memblocks[%d].addr= 0x%.8x, memblocks[%d].size= %d, file: %s, line: %d\n", i
,
471 memory_tracker_check_integrity(char* file, unsigned int file)
472 file - the file name where the check was placed
473 line - the line in file where the check was placed
474 If a padding_size was supplied to vpx_memory_tracker_init()
475 this function will check ea. addr in the list verifying that
476 addr-padding_size and addr+padding_size is filled with pad_value
478 static void memory_tracker_check_integrity(char *file
, unsigned int line
) {
479 if (memtrack
.padding_size
) {
482 unsigned char *p_show_me
,
484 unsigned int tempme
= memtrack
.pad_value
,
487 unsigned char *x_bounds
;
488 struct mem_block
*p
= memtrack
.head
->next
;
491 // x_bounds = (unsigned char*)p->addr;
492 // back up VPX_BYTE_ALIGNMENT
493 // x_bounds -= memtrack.padding_size;
495 if (p
->padded
) { // can the bounds be checked?
496 /*yes, move to the address that was actually allocated
498 x_bounds
= (unsigned char *)(((size_t *)p
->addr
)[-1]);
500 for (i
= 0; i
< memtrack
.padding_size
; i
+= sizeof(unsigned int)) {
501 p_show_me
= (x_bounds
+ i
);
502 p_show_me2
= (unsigned char *)(p
->addr
+ p
->size
+ i
);
504 MEM_TRACK_MEMCPY(&dead1
, p_show_me
, sizeof(unsigned int));
505 MEM_TRACK_MEMCPY(&dead2
, p_show_me2
, sizeof(unsigned int));
507 if ((dead1
!= tempme
) || (dead2
!= tempme
)) {
508 memtrack_log("\n[vpx_mem integrity check failed]:\n"
509 " index[%d,%d] {%s:%d} addr=0x%x, size=%d,"
510 " file: %s, line: %d c0:0x%x c1:0x%x\n",
511 index
, i
, file
, line
, p
->addr
, p
->size
, p
->file
,
512 p
->line
, dead1
, dead2
);
524 memory_tracker_add(size_t addr, unsigned int size,
525 char * file, unsigned int line)
526 Adds an address (addr), it's size, file and line number to our list.
527 Adjusts the total bytes allocated and max bytes allocated if necessary.
528 If memory cannot be allocated the list will be destroyed.
530 void memory_tracker_add(size_t addr
, unsigned int size
,
531 char *file
, unsigned int line
,
533 if (!memory_tracker_lock_mutex()) {
536 p
= MEM_TRACK_MALLOC(sizeof(struct mem_block
));
539 p
->prev
= memtrack
.tail
;
550 memtrack
.current_allocated
+= size
;
552 if (memtrack
.current_allocated
> memtrack
.max_allocated
)
553 memtrack
.max_allocated
= memtrack
.current_allocated
;
555 // memtrack_log("memory_tracker_add: added addr=0x%.8x\n", addr);
557 memory_tracker_unlock_mutex();
559 memtrack_log("memory_tracker_add: error allocating memory!\n");
560 memory_tracker_unlock_mutex();
561 vpx_memory_tracker_destroy();
567 memory_tracker_remove(size_t addr)
568 Removes an address and its corresponding size (if they exist)
569 from the memory tracker list and adjusts the current number
573 -1: if the mutex could not be locked
574 -2: if the addr was not found in the list
576 int memory_tracker_remove(size_t addr
) {
579 if (!memory_tracker_lock_mutex()) {
582 if ((p
= memory_tracker_find(addr
))) {
583 memtrack
.current_allocated
-= p
->size
;
585 p
->prev
->next
= p
->next
;
588 p
->next
->prev
= p
->prev
;
590 memtrack
.tail
= p
->prev
;
596 memtrack_log("memory_tracker_remove(): addr not found in list,"
602 memory_tracker_unlock_mutex();
609 memory_tracker_find(size_t addr)
610 Finds an address in our addrs list
611 NOTE: the mutex MUST be locked in the other internal
612 functions before calling this one. This avoids
613 the need for repeated locking and unlocking as in Remove
614 Returns: pointer to the mem block if found, NULL otherwise
616 static struct mem_block
*memory_tracker_find(size_t addr
) {
617 struct mem_block
*p
= NULL
;
620 p
= memtrack
.head
->next
;
622 while (p
&& (p
->addr
!= addr
))
630 #if !defined(NO_MUTEX)
632 memory_tracker_lock_mutex()
633 Locks the memory tracker mutex with a platform specific call
636 <0: Failure, either the mutex was not initialized
637 or the call to lock the mutex failed
639 static int memory_tracker_lock_mutex() {
642 if (g_b_mem_tracker_inited
) {
645 ret
= pthread_mutex_lock(&memtrack
.mutex
);
646 #elif defined(WIN32) || defined(_WIN32_WCE)
647 ret
= WaitForSingleObject(memtrack
.mutex
, INFINITE
);
648 #elif defined(VXWORKS)
649 ret
= sem_take(memtrack
.mutex
, WAIT_FOREVER
);
653 memtrack_log("memory_tracker_lock_mutex: mutex lock failed\n");
661 memory_tracker_unlock_mutex()
662 Unlocks the memory tracker mutex with a platform specific call
665 <0: Failure, either the mutex was not initialized
666 or the call to unlock the mutex failed
668 static int memory_tracker_unlock_mutex() {
671 if (g_b_mem_tracker_inited
) {
674 ret
= pthread_mutex_unlock(&memtrack
.mutex
);
675 #elif defined(WIN32) || defined(_WIN32_WCE)
676 ret
= !ReleaseMutex(memtrack
.mutex
);
677 #elif defined(VXWORKS)
678 ret
= sem_give(memtrack
.mutex
);
682 memtrack_log("memory_tracker_unlock_mutex: mutex unlock failed\n");
691 vpx_memory_tracker_set_functions
693 Sets the function pointers for the standard library functions.
697 -1: if the use global function pointers is not set.
699 int vpx_memory_tracker_set_functions(mem_track_malloc_func g_malloc_l
700 , mem_track_calloc_func g_calloc_l
701 , mem_track_realloc_func g_realloc_l
702 , mem_track_free_func g_free_l
703 , mem_track_memcpy_func g_memcpy_l
704 , mem_track_memset_func g_memset_l
705 , mem_track_memmove_func g_memmove_l
) {
706 #if USE_GLOBAL_FUNCTION_POINTERS
709 g_malloc
= g_malloc_l
;
712 g_calloc
= g_calloc_l
;
715 g_realloc
= g_realloc_l
;
721 g_memcpy
= g_memcpy_l
;
724 g_memset
= g_memset_l
;
727 g_memmove
= g_memmove_l
;