Fix missing param name in NEON scaler functions
[profile/ivi/libvpx.git] / vpx_mem / vpx_mem_tracker.c
1 /*
2  *  Copyright (c) 2010 The WebM project authors. All Rights Reserved.
3  *
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  */
10
11
12 /*
13   vpx_mem_tracker.c
14
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
24 */
25 #include "vpx_config.h"
26
27 #if defined(__uClinux__)
28 # include <lddk.h>
29 #endif
30
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
40
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>
46
47 #include "include/vpx_mem_tracker.h"
48
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
53
54
55 #ifndef USE_GLOBAL_FUNCTION_POINTERS
56 # define USE_GLOBAL_FUNCTION_POINTERS   0  //use function pointers instead of compiled functions.
57 #endif
58
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
77
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);
87
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
95
96 #ifndef VPX_NO_GLOBALS
97 struct memory_tracker
98 {
99     struct mem_block *head,
100             * tail;
101     int len,
102         totalsize;
103     unsigned int current_allocated,
104              max_allocated;
105
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
116
117     int padding_size,
118         pad_value;
119 };
120
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
125 {
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
137
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);
142
143 /*
144  *
145  * Exposed library functions
146  *
147 */
148
149 /*
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.
156
157     Initializes global memory tracker structure
158     Allocates the head of the list
159 */
160 int vpx_memory_tracker_init(int padding_size, int pad_value)
161 {
162     if (!g_b_mem_tracker_inited)
163     {
164         if ((memtrack.head = (struct mem_block *)
165                              MEM_TRACK_MALLOC(sizeof(struct mem_block))))
166         {
167             int ret;
168
169             MEM_TRACK_MEMSET(memtrack.head, 0, sizeof(struct mem_block));
170
171             memtrack.tail = memtrack.head;
172
173             memtrack.current_allocated = 0;
174             memtrack.max_allocated     = 0;
175
176             memtrack.padding_size = padding_size;
177             memtrack.pad_value    = pad_value;
178
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
194
195             if (ret)
196             {
197                 memtrack_log("vpx_memory_tracker_init: Error creating mutex!\n");
198
199                 MEM_TRACK_FREE(memtrack.head);
200                 memtrack.head = NULL;
201             }
202             else
203             {
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;
209             }
210         }
211     }
212
213     return g_b_mem_tracker_inited;
214 }
215
216 /*
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
220 */
221 void vpx_memory_tracker_destroy()
222 {
223     if (!memory_tracker_lock_mutex())
224     {
225         struct mem_block *p  = memtrack.head,
226                                   * p2 = memtrack.head;
227
228         memory_tracker_dump();
229
230         while (p)
231     {
232             p2 = p;
233             p  = p->next;
234
235             MEM_TRACK_FREE(p2);
236         }
237
238         memtrack.head              = NULL;
239         memtrack.tail              = NULL;
240         memtrack.len               = 0;
241         memtrack.current_allocated = 0;
242         memtrack.max_allocated     = 0;
243
244         if (!g_logging.type && g_logging.file && g_logging.file != stderr)
245         {
246             fclose(g_logging.file);
247             g_logging.file = NULL;
248         }
249
250         memory_tracker_unlock_mutex();
251
252         g_b_mem_tracker_inited = 0;
253     }
254 }
255
256 /*
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
265 */
266 void vpx_memory_tracker_add(size_t addr, unsigned int size,
267                             char *file, unsigned int line,
268                             int padded)
269 {
270     memory_tracker_add(addr, size, file, line, padded);
271 }
272
273 /*
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
280 */
281 int vpx_memory_tracker_remove(size_t addr)
282 {
283     return memory_tracker_remove(addr);
284 }
285
286 /*
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
292 */
293 struct mem_block *vpx_memory_tracker_find(size_t addr)
294 {
295     struct mem_block *p = NULL;
296
297     if (!memory_tracker_lock_mutex())
298     {
299         p = memory_tracker_find(addr);
300         memory_tracker_unlock_mutex();
301     }
302
303     return p;
304 }
305
306 /*
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
311 */
312 void vpx_memory_tracker_dump()
313 {
314     if (!memory_tracker_lock_mutex())
315     {
316         memory_tracker_dump();
317         memory_tracker_unlock_mutex();
318     }
319 }
320
321 /*
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
328 */
329 void vpx_memory_tracker_check_integrity(char *file, unsigned int line)
330 {
331     if (!memory_tracker_lock_mutex())
332     {
333         memory_tracker_check_integrity(file, line);
334         memory_tracker_unlock_mutex();
335     }
336 }
337
338 /*
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
346 */
347 int vpx_memory_tracker_set_log_type(int type, char *option)
348 {
349     int ret = -1;
350
351     switch (type)
352     {
353     case 0:
354         g_logging.type = 0;
355
356         if (!option)
357         {
358             g_logging.file = stderr;
359             ret = 0;
360         }
361         else
362         {
363             if ((g_logging.file = fopen((char *)option, "w")))
364                 ret = 0;
365         }
366
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;
376     }
377
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");
382
383     return ret;
384 }
385
386 /*
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
392 */
393 int vpx_memory_tracker_set_log_func(void *userdata,
394                                     void(*logfunc)(void *userdata,
395                                             const char *fmt, va_list args))
396 {
397     int ret = -1;
398
399     if (logfunc)
400     {
401         g_logging.type     = -1;
402         g_logging.userdata = userdata;
403         g_logging.func     = logfunc;
404         ret = 0;
405     }
406
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");
411
412     return ret;
413 }
414
415 /*
416  *
417  * END - Exposed library functions
418  *
419 */
420
421
422 /*
423  *
424  * Internal library functions
425  *
426 */
427
428 static void memtrack_log(const char *fmt, ...)
429 {
430     va_list list;
431
432     va_start(list, fmt);
433
434     switch (g_logging.type)
435     {
436     case -1:
437
438         if (g_logging.func)
439             g_logging.func(g_logging.userdata, fmt, list);
440
441         break;
442     case 0:
443
444         if (g_logging.file)
445         {
446             vfprintf(g_logging.file, fmt, list);
447             fflush(g_logging.file);
448         }
449
450         break;
451 #if defined(WIN32) && !defined(_WIN32_WCE)
452     case 1:
453     {
454         char temp[1024];
455         _vsnprintf(temp, sizeof(temp) / sizeof(char) - 1, fmt, list);
456         OutputDebugString(temp);
457     }
458     break;
459 #endif
460     default:
461         break;
462     }
463
464     va_end(list);
465 }
466
467 /*
468     memory_tracker_dump()
469     Dumps the current contents of the global memory allocation list
470 */
471 static void memory_tracker_dump()
472 {
473     int i = 0;
474     struct mem_block *p = (memtrack.head ? memtrack.head->next : NULL);
475
476     memtrack_log("\n_currently Allocated= %d; Max allocated= %d\n",
477                  memtrack.current_allocated, memtrack.max_allocated);
478
479     while (p)
480     {
481 #if defined(WIN32) && !defined(_WIN32_WCE)
482
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);
495
496         p = p->next;
497         ++i;
498     }
499
500     memtrack_log("\n");
501 }
502
503 /*
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
510 */
511 static void memory_tracker_check_integrity(char *file, unsigned int line)
512 {
513     if (memtrack.padding_size)
514     {
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;
524
525         while (p)
526         {
527             //x_bounds = (unsigned char*)p->addr;
528             //back up VPX_BYTE_ALIGNMENT
529             //x_bounds -= memtrack.padding_size;
530
531             if (p->padded)   // can the bounds be checked?
532             {
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]);
536
537                 for (i = 0; i < memtrack.padding_size; i += sizeof(unsigned int))
538                 {
539                     p_show_me = (x_bounds + i);
540                     p_show_me2 = (unsigned char *)(p->addr + p->size + i);
541
542                     MEM_TRACK_MEMCPY(&dead1, p_show_me, sizeof(unsigned int));
543                     MEM_TRACK_MEMCPY(&dead2, p_show_me2, sizeof(unsigned int));
544
545                     if ((dead1 != tempme) || (dead2 != tempme))
546                     {
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);
552                     }
553                 }
554             }
555
556             ++index;
557             p = p->next;
558         }
559     }
560 }
561
562 /*
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.
568 */
569 void memory_tracker_add(size_t addr, unsigned int size,
570                         char *file, unsigned int line,
571                         int padded)
572 {
573     if (!memory_tracker_lock_mutex())
574     {
575         struct mem_block *p;
576
577         p = MEM_TRACK_MALLOC(sizeof(struct mem_block));
578
579         if (p)
580         {
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;
589
590             memtrack.tail = p;
591
592             memtrack.current_allocated += size;
593
594             if (memtrack.current_allocated > memtrack.max_allocated)
595                 memtrack.max_allocated = memtrack.current_allocated;
596
597             //memtrack_log("memory_tracker_add: added addr=0x%.8x\n", addr);
598
599             memory_tracker_unlock_mutex();
600         }
601         else
602         {
603             memtrack_log("memory_tracker_add: error allocating memory!\n");
604             memory_tracker_unlock_mutex();
605             vpx_memory_tracker_destroy();
606         }
607     }
608 }
609
610 /*
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
619 */
620 int memory_tracker_remove(size_t addr)
621 {
622     int ret = -1;
623
624     if (!memory_tracker_lock_mutex())
625     {
626         struct mem_block *p;
627
628         if ((p = memory_tracker_find(addr)))
629         {
630             memtrack.current_allocated -= p->size;
631
632             p->prev->next = p->next;
633
634             if (p->next)
635                 p->next->prev = p->prev;
636             else
637                 memtrack.tail = p->prev;
638
639             ret = 0;
640             MEM_TRACK_FREE(p);
641         }
642         else
643         {
644             if (addr)
645                 memtrack_log("memory_tracker_remove(): addr not found in list,"
646                              " 0x%.8x\n", addr);
647
648             ret = -2;
649         }
650
651         memory_tracker_unlock_mutex();
652     }
653
654     return ret;
655 }
656
657 /*
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
664 */
665 static struct mem_block *memory_tracker_find(size_t addr)
666 {
667     struct mem_block *p = NULL;
668
669     if (memtrack.head)
670     {
671         p = memtrack.head->next;
672
673         while (p && (p->addr != addr))
674             p = p->next;
675     }
676
677     return p;
678 }
679
680
681 #if !defined(NO_MUTEX)
682 /*
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
689 */
690 static int memory_tracker_lock_mutex()
691 {
692     int ret = -1;
693
694     if (g_b_mem_tracker_inited)
695     {
696
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
704
705         if (ret)
706         {
707             memtrack_log("memory_tracker_lock_mutex: mutex lock failed\n");
708         }
709     }
710
711     return ret;
712 }
713
714 /*
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
721 */
722 static int memory_tracker_unlock_mutex()
723 {
724     int ret = -1;
725
726     if (g_b_mem_tracker_inited)
727     {
728
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
736
737         if (ret)
738         {
739             memtrack_log("memory_tracker_unlock_mutex: mutex unlock failed\n");
740         }
741     }
742
743     return ret;
744 }
745 #endif
746
747 /*
748     vpx_memory_tracker_set_functions
749
750     Sets the function pointers for the standard library functions.
751
752     Return:
753       0: on success
754       -1: if the use global function pointers is not set.
755 */
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)
763 {
764 #if USE_GLOBAL_FUNCTION_POINTERS
765
766     if (g_malloc_l)
767         g_malloc = g_malloc_l;
768
769     if (g_calloc_l)
770         g_calloc = g_calloc_l;
771
772     if (g_realloc_l)
773         g_realloc = g_realloc_l;
774
775     if (g_free_l)
776         g_free = g_free_l;
777
778     if (g_memcpy_l)
779         g_memcpy = g_memcpy_l;
780
781     if (g_memset_l)
782         g_memset = g_memset_l;
783
784     if (g_memmove_l)
785         g_memmove = g_memmove_l;
786
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
798 }