Merge "Fix building with --disable-postproc" into cayuga
[libvpx.git] / vpx_mem / vpx_mem_tracker.c
blob9e8623a9a30d2363eb0cd386e2fe778a62c4910e
1 /*
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.
9 */
13 vpx_mem_tracker.c
15 jwz 2003-09-30:
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
18 to be thread safe.
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__)
28 # include <lddk.h>
29 #endif
31 #if HAVE_PTHREAD_H
32 # include <pthread.h>
33 #elif defined(WIN32) || defined(_WIN32_WCE)
34 # define WIN32_LEAN_AND_MEAN
35 # include <windows.h>
36 # include <winbase.h>
37 #elif defined(VXWORKS)
38 # include <sem_lib.h>
39 #endif
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h> //VXWORKS doesn't have a malloc/memory.h file,
44 //this should pull in malloc,free,etc.
45 #include <stdarg.h>
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
51 #undef vpx_memcpy
52 #undef vpx_memset
55 #ifndef USE_GLOBAL_FUNCTION_POINTERS
56 # define USE_GLOBAL_FUNCTION_POINTERS 0 //use function pointers instead of compiled functions.
57 #endif
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
71 #else
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,
84 int padded);
85 static int memory_tracker_remove(size_t addr);
86 static struct mem_block *memory_tracker_find(size_t addr);
88 #if defined(NO_MUTEX)
89 # define memory_tracker_lock_mutex() (!g_b_mem_tracker_inited)
90 # define memory_tracker_unlock_mutex()
91 #else
92 static int memory_tracker_lock_mutex();
93 static int memory_tracker_unlock_mutex();
94 #endif
96 #ifndef VPX_NO_GLOBALS
97 struct memory_tracker
99 struct mem_block *head,
100 * tail;
101 int len,
102 totalsize;
103 unsigned int current_allocated,
104 max_allocated;
106 #if HAVE_PTHREAD_H
107 pthread_mutex_t mutex;
108 #elif defined(WIN32) || defined(_WIN32_WCE)
109 HANDLE mutex;
110 #elif defined(VXWORKS)
111 SEM_ID mutex;
112 #elif defined(NO_MUTEX)
113 #else
114 #error "No mutex type defined for this platform!"
115 #endif
117 int padding_size,
118 pad_value;
121 static struct memory_tracker memtrack; //our global memory allocation list
122 static int g_b_mem_tracker_inited = 0; //indicates whether the global list has
123 //been initialized (1:yes/0:no)
124 static struct
126 FILE *file;
127 int type;
128 void (*func)(void *userdata, const char *fmt, va_list args);
129 void *userdata;
130 } g_logging = {NULL, 0, NULL, NULL};
131 #else
132 # include "vpx_global_handling.h"
133 #define g_b_mem_tracker_inited vpxglobalm(vpxmem,g_b_mem_tracker_inited)
134 #define g_logging vpxglobalm(vpxmem,g_logging)
135 #define memtrack vpxglobalm(vpxmem,memtrack)
136 #endif // #ifndef VPX_NO_GLOBALS
138 extern void *vpx_malloc(size_t size);
139 extern void vpx_free(void *memblk);
140 extern void *vpx_memcpy(void *dest, const void *src, size_t length);
141 extern void *vpx_memset(void *dest, int val, size_t length);
145 * Exposed library functions
150 vpx_memory_tracker_init(int padding_size, int pad_value)
151 padding_size - the size of the padding before and after each mem addr.
152 Values > 0 indicate that integrity checks can be performed
153 by inspecting these areas.
154 pad_value - the initial value within the padding area before and after
155 each mem addr.
157 Initializes global memory tracker structure
158 Allocates the head of the list
160 int vpx_memory_tracker_init(int padding_size, int pad_value)
162 if (!g_b_mem_tracker_inited)
164 if ((memtrack.head = (struct mem_block *)
165 MEM_TRACK_MALLOC(sizeof(struct mem_block))))
167 int ret;
169 MEM_TRACK_MEMSET(memtrack.head, 0, sizeof(struct mem_block));
171 memtrack.tail = memtrack.head;
173 memtrack.current_allocated = 0;
174 memtrack.max_allocated = 0;
176 memtrack.padding_size = padding_size;
177 memtrack.pad_value = pad_value;
179 #if HAVE_PTHREAD_H
180 ret = pthread_mutex_init(&memtrack.mutex,
181 NULL); /*mutex attributes (NULL=default)*/
182 #elif defined(WIN32) || defined(_WIN32_WCE)
183 memtrack.mutex = CreateMutex(NULL, /*security attributes*/
184 FALSE, /*we don't want initial ownership*/
185 NULL); /*mutex name*/
186 ret = !memtrack.mutex;
187 #elif defined(VXWORKS)
188 memtrack.mutex = sem_bcreate(SEM_Q_FIFO, /*SEM_Q_FIFO non-priority based mutex*/
189 SEM_FULL); /*SEM_FULL initial state is unlocked*/
190 ret = !memtrack.mutex;
191 #elif defined(NO_MUTEX)
192 ret = 0;
193 #endif
195 if (ret)
197 memtrack_log("vpx_memory_tracker_init: Error creating mutex!\n");
199 MEM_TRACK_FREE(memtrack.head);
200 memtrack.head = NULL;
202 else
204 memtrack_log("Memory Tracker init'd, v."vpx_mem_tracker_version" pad_size:%d pad_val:0x%x %d\n"
205 , padding_size
206 , pad_value
207 , pad_value);
208 g_b_mem_tracker_inited = 1;
213 return g_b_mem_tracker_inited;
217 vpx_memory_tracker_destroy()
218 If our global struct was initialized zeros out all its members,
219 frees memory and destroys it's mutex
221 void vpx_memory_tracker_destroy()
223 if (!memory_tracker_lock_mutex())
225 struct mem_block *p = memtrack.head,
226 * p2 = memtrack.head;
228 memory_tracker_dump();
230 while (p)
232 p2 = p;
233 p = p->next;
235 MEM_TRACK_FREE(p2);
238 memtrack.head = NULL;
239 memtrack.tail = NULL;
240 memtrack.len = 0;
241 memtrack.current_allocated = 0;
242 memtrack.max_allocated = 0;
244 if (!g_logging.type && g_logging.file && g_logging.file != stderr)
246 fclose(g_logging.file);
247 g_logging.file = NULL;
250 memory_tracker_unlock_mutex();
252 g_b_mem_tracker_inited = 0;
257 vpx_memory_tracker_add(size_t addr, unsigned int size,
258 char * file, unsigned int line)
259 addr - memory address to be added to list
260 size - size of addr
261 file - the file addr was referenced from
262 line - the line in file addr was referenced from
263 Adds memory address addr, it's size, file and line it came from
264 to the global list via the thread safe internal library function
266 void vpx_memory_tracker_add(size_t addr, unsigned int size,
267 char *file, unsigned int line,
268 int padded)
270 memory_tracker_add(addr, size, file, line, padded);
274 vpx_memory_tracker_remove(size_t addr)
275 addr - memory address to be removed from list
276 Removes addr from the global list via the thread safe
277 internal remove function
278 Return:
279 Same as described for memory_tracker_remove
281 int vpx_memory_tracker_remove(size_t addr)
283 return memory_tracker_remove(addr);
287 vpx_memory_tracker_find(size_t addr)
288 addr - address to be found in list
289 Return:
290 If found, pointer to the memory block that matches addr
291 NULL otherwise
293 struct mem_block *vpx_memory_tracker_find(size_t addr)
295 struct mem_block *p = NULL;
297 if (!memory_tracker_lock_mutex())
299 p = memory_tracker_find(addr);
300 memory_tracker_unlock_mutex();
303 return p;
307 vpx_memory_tracker_dump()
308 Locks the memory tracker's mutex and calls the internal
309 library function to dump the current contents of the
310 global memory allocation list
312 void vpx_memory_tracker_dump()
314 if (!memory_tracker_lock_mutex())
316 memory_tracker_dump();
317 memory_tracker_unlock_mutex();
322 vpx_memory_tracker_check_integrity(char* file, unsigned int line)
323 file - The file name where the check was placed
324 line - The line in file where the check was placed
325 Locks the memory tracker's mutex and calls the internal
326 integrity check function to inspect every address in the global
327 memory allocation list
329 void vpx_memory_tracker_check_integrity(char *file, unsigned int line)
331 if (!memory_tracker_lock_mutex())
333 memory_tracker_check_integrity(file, line);
334 memory_tracker_unlock_mutex();
339 vpx_memory_tracker_set_log_type
340 Sets the logging type for the memory tracker. Based on the value it will
341 direct its output to the appropriate place.
342 Return:
343 0: on success
344 -1: if the logging type could not be set, because the value was invalid
345 or because a file could not be opened
347 int vpx_memory_tracker_set_log_type(int type, char *option)
349 int ret = -1;
351 switch (type)
353 case 0:
354 g_logging.type = 0;
356 if (!option)
358 g_logging.file = stderr;
359 ret = 0;
361 else
363 if ((g_logging.file = fopen((char *)option, "w")))
364 ret = 0;
367 break;
368 #if defined(WIN32) && !defined(_WIN32_WCE)
369 case 1:
370 g_logging.type = type;
371 ret = 0;
372 break;
373 #endif
374 default:
375 break;
378 //output the version to the new logging destination
379 if (!ret)
380 memtrack_log("Memory Tracker logging initialized, "
381 "Memory Tracker v."vpx_mem_tracker_version"\n");
383 return ret;
387 vpx_memory_tracker_set_log_func
388 Sets a logging function to be used by the memory tracker.
389 Return:
390 0: on success
391 -1: if the logging type could not be set because logfunc was NULL
393 int vpx_memory_tracker_set_log_func(void *userdata,
394 void(*logfunc)(void *userdata,
395 const char *fmt, va_list args))
397 int ret = -1;
399 if (logfunc)
401 g_logging.type = -1;
402 g_logging.userdata = userdata;
403 g_logging.func = logfunc;
404 ret = 0;
407 //output the version to the new logging destination
408 if (!ret)
409 memtrack_log("Memory Tracker logging initialized, "
410 "Memory Tracker v."vpx_mem_tracker_version"\n");
412 return ret;
417 * END - Exposed library functions
424 * Internal library functions
428 static void memtrack_log(const char *fmt, ...)
430 va_list list;
432 va_start(list, fmt);
434 switch (g_logging.type)
436 case -1:
438 if (g_logging.func)
439 g_logging.func(g_logging.userdata, fmt, list);
441 break;
442 case 0:
444 if (g_logging.file)
446 vfprintf(g_logging.file, fmt, list);
447 fflush(g_logging.file);
450 break;
451 #if defined(WIN32) && !defined(_WIN32_WCE)
452 case 1:
454 char temp[1024];
455 _vsnprintf(temp, sizeof(temp) / sizeof(char) - 1, fmt, list);
456 OutputDebugString(temp);
458 break;
459 #endif
460 default:
461 break;
464 va_end(list);
468 memory_tracker_dump()
469 Dumps the current contents of the global memory allocation list
471 static void memory_tracker_dump()
473 int i = 0;
474 struct mem_block *p = (memtrack.head ? memtrack.head->next : NULL);
476 memtrack_log("\n_currently Allocated= %d; Max allocated= %d\n",
477 memtrack.current_allocated, memtrack.max_allocated);
479 while (p)
481 #if defined(WIN32) && !defined(_WIN32_WCE)
483 /*when using outputdebugstring, output filenames so they
484 can be clicked to be opened in visual studio*/
485 if (g_logging.type == 1)
486 memtrack_log("memblocks[%d].addr= 0x%.8x, memblocks[%d].size= %d, file:\n"
487 " %s(%d):\n", i,
488 p->addr, i, p->size,
489 p->file, p->line);
490 else
491 #endif
492 memtrack_log("memblocks[%d].addr= 0x%.8x, memblocks[%d].size= %d, file: %s, line: %d\n", i,
493 p->addr, i, p->size,
494 p->file, p->line);
496 p = p->next;
497 ++i;
500 memtrack_log("\n");
504 memory_tracker_check_integrity(char* file, unsigned int file)
505 file - the file name where the check was placed
506 line - the line in file where the check was placed
507 If a padding_size was supplied to vpx_memory_tracker_init()
508 this function will check ea. addr in the list verifying that
509 addr-padding_size and addr+padding_size is filled with pad_value
511 static void memory_tracker_check_integrity(char *file, unsigned int line)
513 if (memtrack.padding_size)
515 int i,
516 index = 0;
517 unsigned char *p_show_me,
518 * p_show_me2;
519 unsigned int tempme = memtrack.pad_value,
520 dead1,
521 dead2;
522 unsigned char *x_bounds;
523 struct mem_block *p = memtrack.head->next;
525 while (p)
527 //x_bounds = (unsigned char*)p->addr;
528 //back up VPX_BYTE_ALIGNMENT
529 //x_bounds -= memtrack.padding_size;
531 if (p->padded) // can the bounds be checked?
533 /*yes, move to the address that was actually allocated
534 by the vpx_* calls*/
535 x_bounds = (unsigned char *)(((size_t *)p->addr)[-1]);
537 for (i = 0; i < memtrack.padding_size; i += sizeof(unsigned int))
539 p_show_me = (x_bounds + i);
540 p_show_me2 = (unsigned char *)(p->addr + p->size + i);
542 MEM_TRACK_MEMCPY(&dead1, p_show_me, sizeof(unsigned int));
543 MEM_TRACK_MEMCPY(&dead2, p_show_me2, sizeof(unsigned int));
545 if ((dead1 != tempme) || (dead2 != tempme))
547 memtrack_log("\n[vpx_mem integrity check failed]:\n"
548 " index[%d,%d] {%s:%d} addr=0x%x, size=%d,"
549 " file: %s, line: %d c0:0x%x c1:0x%x\n",
550 index, i, file, line, p->addr, p->size, p->file,
551 p->line, dead1, dead2);
556 ++index;
557 p = p->next;
563 memory_tracker_add(size_t addr, unsigned int size,
564 char * file, unsigned int line)
565 Adds an address (addr), it's size, file and line number to our list.
566 Adjusts the total bytes allocated and max bytes allocated if necessary.
567 If memory cannot be allocated the list will be destroyed.
569 void memory_tracker_add(size_t addr, unsigned int size,
570 char *file, unsigned int line,
571 int padded)
573 if (!memory_tracker_lock_mutex())
575 struct mem_block *p;
577 p = MEM_TRACK_MALLOC(sizeof(struct mem_block));
579 if (p)
581 p->prev = memtrack.tail;
582 p->prev->next = p;
583 p->addr = addr;
584 p->size = size;
585 p->line = line;
586 p->file = file;
587 p->padded = padded;
588 p->next = NULL;
590 memtrack.tail = p;
592 memtrack.current_allocated += size;
594 if (memtrack.current_allocated > memtrack.max_allocated)
595 memtrack.max_allocated = memtrack.current_allocated;
597 //memtrack_log("memory_tracker_add: added addr=0x%.8x\n", addr);
599 memory_tracker_unlock_mutex();
601 else
603 memtrack_log("memory_tracker_add: error allocating memory!\n");
604 memory_tracker_unlock_mutex();
605 vpx_memory_tracker_destroy();
611 memory_tracker_remove(size_t addr)
612 Removes an address and its corresponding size (if they exist)
613 from the memory tracker list and adjusts the current number
614 of bytes allocated.
615 Return:
616 0: on success
617 -1: if the mutex could not be locked
618 -2: if the addr was not found in the list
620 int memory_tracker_remove(size_t addr)
622 int ret = -1;
624 if (!memory_tracker_lock_mutex())
626 struct mem_block *p;
628 if ((p = memory_tracker_find(addr)))
630 memtrack.current_allocated -= p->size;
632 p->prev->next = p->next;
634 if (p->next)
635 p->next->prev = p->prev;
636 else
637 memtrack.tail = p->prev;
639 ret = 0;
640 MEM_TRACK_FREE(p);
642 else
644 if (addr)
645 memtrack_log("memory_tracker_remove(): addr not found in list,"
646 " 0x%.8x\n", addr);
648 ret = -2;
651 memory_tracker_unlock_mutex();
654 return ret;
658 memory_tracker_find(size_t addr)
659 Finds an address in our addrs list
660 NOTE: the mutex MUST be locked in the other internal
661 functions before calling this one. This avoids
662 the need for repeated locking and unlocking as in Remove
663 Returns: pointer to the mem block if found, NULL otherwise
665 static struct mem_block *memory_tracker_find(size_t addr)
667 struct mem_block *p = NULL;
669 if (memtrack.head)
671 p = memtrack.head->next;
673 while (p && (p->addr != addr))
674 p = p->next;
677 return p;
681 #if !defined(NO_MUTEX)
683 memory_tracker_lock_mutex()
684 Locks the memory tracker mutex with a platform specific call
685 Returns:
686 0: Success
687 <0: Failure, either the mutex was not initialized
688 or the call to lock the mutex failed
690 static int memory_tracker_lock_mutex()
692 int ret = -1;
694 if (g_b_mem_tracker_inited)
697 #if HAVE_PTHREAD_H
698 ret = pthread_mutex_lock(&memtrack.mutex);
699 #elif defined(WIN32) || defined(_WIN32_WCE)
700 ret = WaitForSingleObject(memtrack.mutex, INFINITE);
701 #elif defined(VXWORKS)
702 ret = sem_take(memtrack.mutex, WAIT_FOREVER);
703 #endif
705 if (ret)
707 memtrack_log("memory_tracker_lock_mutex: mutex lock failed\n");
711 return ret;
715 memory_tracker_unlock_mutex()
716 Unlocks the memory tracker mutex with a platform specific call
717 Returns:
718 0: Success
719 <0: Failure, either the mutex was not initialized
720 or the call to unlock the mutex failed
722 static int memory_tracker_unlock_mutex()
724 int ret = -1;
726 if (g_b_mem_tracker_inited)
729 #if HAVE_PTHREAD_H
730 ret = pthread_mutex_unlock(&memtrack.mutex);
731 #elif defined(WIN32) || defined(_WIN32_WCE)
732 ret = !ReleaseMutex(memtrack.mutex);
733 #elif defined(VXWORKS)
734 ret = sem_give(memtrack.mutex);
735 #endif
737 if (ret)
739 memtrack_log("memory_tracker_unlock_mutex: mutex unlock failed\n");
743 return ret;
745 #endif
748 vpx_memory_tracker_set_functions
750 Sets the function pointers for the standard library functions.
752 Return:
753 0: on success
754 -1: if the use global function pointers is not set.
756 int vpx_memory_tracker_set_functions(mem_track_malloc_func g_malloc_l
757 , mem_track_calloc_func g_calloc_l
758 , mem_track_realloc_func g_realloc_l
759 , mem_track_free_func g_free_l
760 , mem_track_memcpy_func g_memcpy_l
761 , mem_track_memset_func g_memset_l
762 , mem_track_memmove_func g_memmove_l)
764 #if USE_GLOBAL_FUNCTION_POINTERS
766 if (g_malloc_l)
767 g_malloc = g_malloc_l;
769 if (g_calloc_l)
770 g_calloc = g_calloc_l;
772 if (g_realloc_l)
773 g_realloc = g_realloc_l;
775 if (g_free_l)
776 g_free = g_free_l;
778 if (g_memcpy_l)
779 g_memcpy = g_memcpy_l;
781 if (g_memset_l)
782 g_memset = g_memset_l;
784 if (g_memmove_l)
785 g_memmove = g_memmove_l;
787 return 0;
788 #else
789 (void)g_malloc_l;
790 (void)g_calloc_l;
791 (void)g_realloc_l;
792 (void)g_free_l;
793 (void)g_memcpy_l;
794 (void)g_memset_l;
795 (void)g_memmove_l;
796 return -1;
797 #endif