Merge "vp8e - boolcoder unit test"
[profile/ivi/libvpx.git] / vpx_mem / vpx_mem.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 #define __VPX_MEM_C__
13
14 #include "vpx_mem.h"
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include "include/vpx_mem_intrnl.h"
19
20 #if CONFIG_MEM_TRACKER
21 #ifndef VPX_NO_GLOBALS
22 static unsigned long g_alloc_count = 0;
23 #else
24 #include "vpx_global_handling.h"
25 #define g_alloc_count vpxglobalm(vpxmem,g_alloc_count)
26 #endif
27 #endif
28
29 #if CONFIG_MEM_MANAGER
30 # include "heapmm.h"
31 # include "hmm_intrnl.h"
32
33 # define SHIFT_HMM_ADDR_ALIGN_UNIT 5
34 # define TOTAL_MEMORY_TO_ALLOCATE  20971520 /* 20 * 1024 * 1024 */
35
36 # define MM_DYNAMIC_MEMORY 1
37 # if MM_DYNAMIC_MEMORY
38 static unsigned char *g_p_mng_memory_raw = NULL;
39 static unsigned char *g_p_mng_memory     = NULL;
40 # else
41 static unsigned char g_p_mng_memory[TOTAL_MEMORY_TO_ALLOCATE];
42 # endif
43
44 static size_t g_mm_memory_size = TOTAL_MEMORY_TO_ALLOCATE;
45
46 static hmm_descriptor hmm_d;
47 static int g_mng_memory_allocated = 0;
48
49 static int vpx_mm_create_heap_memory();
50 static void *vpx_mm_realloc(void *memblk, size_t size);
51 #endif /*CONFIG_MEM_MANAGER*/
52
53 #if USE_GLOBAL_FUNCTION_POINTERS
54 struct GLOBAL_FUNC_POINTERS
55 {
56     g_malloc_func g_malloc;
57     g_calloc_func g_calloc;
58     g_realloc_func g_realloc;
59     g_free_func g_free;
60     g_memcpy_func g_memcpy;
61     g_memset_func g_memset;
62     g_memmove_func g_memmove;
63 } *g_func = NULL;
64
65 # define VPX_MALLOC_L  g_func->g_malloc
66 # define VPX_REALLOC_L g_func->g_realloc
67 # define VPX_FREE_L    g_func->g_free
68 # define VPX_MEMCPY_L  g_func->g_memcpy
69 # define VPX_MEMSET_L  g_func->g_memset
70 # define VPX_MEMMOVE_L g_func->g_memmove
71 #else
72 # define VPX_MALLOC_L  malloc
73 # define VPX_REALLOC_L realloc
74 # define VPX_FREE_L    free
75 # define VPX_MEMCPY_L  memcpy
76 # define VPX_MEMSET_L  memset
77 # define VPX_MEMMOVE_L memmove
78 #endif /* USE_GLOBAL_FUNCTION_POINTERS */
79
80 unsigned int vpx_mem_get_version()
81 {
82     unsigned int ver = ((unsigned int)(unsigned char)VPX_MEM_VERSION_CHIEF << 24 |
83                         (unsigned int)(unsigned char)VPX_MEM_VERSION_MAJOR << 16 |
84                         (unsigned int)(unsigned char)VPX_MEM_VERSION_MINOR << 8  |
85                         (unsigned int)(unsigned char)VPX_MEM_VERSION_PATCH);
86     return ver;
87 }
88
89 int vpx_mem_set_heap_size(size_t size)
90 {
91     int ret = -1;
92
93 #if CONFIG_MEM_MANAGER
94 #if MM_DYNAMIC_MEMORY
95
96     if (!g_mng_memory_allocated && size)
97     {
98         g_mm_memory_size = size;
99         ret = 0;
100     }
101     else
102         ret = -3;
103
104 #else
105     ret = -2;
106 #endif
107 #else
108     (void)size;
109 #endif
110
111     return ret;
112 }
113
114 void *vpx_memalign(size_t align, size_t size)
115 {
116     void *addr,
117          * x = NULL;
118
119 #if CONFIG_MEM_MANAGER
120     int number_aau;
121
122     if (vpx_mm_create_heap_memory() < 0)
123     {
124         _P(printf("[vpx][mm] ERROR vpx_memalign() Couldn't create memory for Heap.\n");)
125     }
126
127     number_aau = ((size + align - 1 + ADDRESS_STORAGE_SIZE) >>
128                   SHIFT_HMM_ADDR_ALIGN_UNIT) + 1;
129
130     addr = hmm_alloc(&hmm_d, number_aau);
131 #else
132     addr = VPX_MALLOC_L(size + align - 1 + ADDRESS_STORAGE_SIZE);
133 #endif /*CONFIG_MEM_MANAGER*/
134
135     if (addr)
136     {
137         x = align_addr((unsigned char *)addr + ADDRESS_STORAGE_SIZE, (int)align);
138         /* save the actual malloc address */
139         ((size_t *)x)[-1] = (size_t)addr;
140     }
141
142     return x;
143 }
144
145 void *vpx_malloc(size_t size)
146 {
147     return vpx_memalign(DEFAULT_ALIGNMENT, size);
148 }
149
150 void *vpx_calloc(size_t num, size_t size)
151 {
152     void *x;
153
154     x = vpx_memalign(DEFAULT_ALIGNMENT, num * size);
155
156     if (x)
157         VPX_MEMSET_L(x, 0, num * size);
158
159     return x;
160 }
161
162 void *vpx_realloc(void *memblk, size_t size)
163 {
164     void *addr,
165          * new_addr = NULL;
166     int align = DEFAULT_ALIGNMENT;
167
168     /*
169     The realloc() function changes the size of the object pointed to by
170     ptr to the size specified by size, and returns a pointer to the
171     possibly moved block. The contents are unchanged up to the lesser
172     of the new and old sizes. If ptr is null, realloc() behaves like
173     malloc() for the specified size. If size is zero (0) and ptr is
174     not a null pointer, the object pointed to is freed.
175     */
176     if (!memblk)
177         new_addr = vpx_malloc(size);
178     else if (!size)
179         vpx_free(memblk);
180     else
181     {
182         addr   = (void *)(((size_t *)memblk)[-1]);
183         memblk = NULL;
184
185 #if CONFIG_MEM_MANAGER
186         new_addr = vpx_mm_realloc(addr, size + align + ADDRESS_STORAGE_SIZE);
187 #else
188         new_addr = VPX_REALLOC_L(addr, size + align + ADDRESS_STORAGE_SIZE);
189 #endif
190
191         if (new_addr)
192         {
193             addr = new_addr;
194             new_addr = (void *)(((size_t)
195                                  ((unsigned char *)new_addr + ADDRESS_STORAGE_SIZE) + (align - 1)) &
196                                 (size_t) - align);
197             /* save the actual malloc address */
198             ((size_t *)new_addr)[-1] = (size_t)addr;
199         }
200     }
201
202     return new_addr;
203 }
204
205 void vpx_free(void *memblk)
206 {
207     if (memblk)
208     {
209         void *addr = (void *)(((size_t *)memblk)[-1]);
210 #if CONFIG_MEM_MANAGER
211         hmm_free(&hmm_d, addr);
212 #else
213         VPX_FREE_L(addr);
214 #endif
215     }
216 }
217
218 #if CONFIG_MEM_TRACKER
219 void *xvpx_memalign(size_t align, size_t size, char *file, int line)
220 {
221 #if TRY_BOUNDS_CHECK
222     unsigned char *x_bounds;
223 #endif
224
225     void *x;
226
227     if (g_alloc_count == 0)
228     {
229 #if TRY_BOUNDS_CHECK
230         int i_rv = vpx_memory_tracker_init(BOUNDS_CHECK_PAD_SIZE, BOUNDS_CHECK_VALUE);
231 #else
232         int i_rv = vpx_memory_tracker_init(0, 0);
233 #endif
234
235         if (i_rv < 0)
236         {
237             _P(printf("ERROR xvpx_malloc MEM_TRACK_USAGE error vpx_memory_tracker_init().\n");)
238         }
239     }
240
241 #if TRY_BOUNDS_CHECK
242     {
243         int i;
244         unsigned int tempme = BOUNDS_CHECK_VALUE;
245
246         x_bounds = vpx_memalign(align, size + (BOUNDS_CHECK_PAD_SIZE * 2));
247
248         if (x_bounds)
249         {
250             /*we're aligning the address twice here but to keep things
251               consistent we want to have the padding come before the stored
252               address so no matter what free function gets called we will
253               attempt to free the correct address*/
254             x_bounds = (unsigned char *)(((size_t *)x_bounds)[-1]);
255             x = align_addr(x_bounds + BOUNDS_CHECK_PAD_SIZE + ADDRESS_STORAGE_SIZE,
256                            (int)align);
257             /* save the actual malloc address */
258             ((size_t *)x)[-1] = (size_t)x_bounds;
259
260             for (i = 0; i < BOUNDS_CHECK_PAD_SIZE; i += sizeof(unsigned int))
261             {
262                 VPX_MEMCPY_L(x_bounds + i, &tempme, sizeof(unsigned int));
263                 VPX_MEMCPY_L((unsigned char *)x + size + i,
264                              &tempme, sizeof(unsigned int));
265             }
266         }
267         else
268             x = NULL;
269     }
270 #else
271     x = vpx_memalign(align, size);
272 #endif /*TRY_BOUNDS_CHECK*/
273
274     g_alloc_count++;
275
276     vpx_memory_tracker_add((size_t)x, (unsigned int)size, file, line, 1);
277
278     return x;
279 }
280
281 void *xvpx_malloc(size_t size, char *file, int line)
282 {
283     return xvpx_memalign(DEFAULT_ALIGNMENT, size, file, line);
284 }
285
286 void *xvpx_calloc(size_t num, size_t size, char *file, int line)
287 {
288     void *x = xvpx_memalign(DEFAULT_ALIGNMENT, num * size, file, line);
289
290     if (x)
291         VPX_MEMSET_L(x, 0, num * size);
292
293     return x;
294 }
295
296 void *xvpx_realloc(void *memblk, size_t size, char *file, int line)
297 {
298     struct mem_block *p = NULL;
299     int orig_size = 0,
300         orig_line = 0;
301     char *orig_file = NULL;
302
303 #if TRY_BOUNDS_CHECK
304     unsigned char *x_bounds = memblk ?
305                               (unsigned char *)(((size_t *)memblk)[-1]) :
306                               NULL;
307 #endif
308
309     void *x;
310
311     if (g_alloc_count == 0)
312     {
313 #if TRY_BOUNDS_CHECK
314
315         if (!vpx_memory_tracker_init(BOUNDS_CHECK_PAD_SIZE, BOUNDS_CHECK_VALUE))
316 #else
317         if (!vpx_memory_tracker_init(0, 0))
318 #endif
319         {
320             _P(printf("ERROR xvpx_malloc MEM_TRACK_USAGE error vpx_memory_tracker_init().\n");)
321         }
322     }
323
324     if ((p = vpx_memory_tracker_find((size_t)memblk)))
325     {
326         orig_size = p->size;
327         orig_file = p->file;
328         orig_line = p->line;
329     }
330
331 #if TRY_BOUNDS_CHECK_ON_FREE
332     vpx_memory_tracker_check_integrity(file, line);
333 #endif
334
335     /* have to do this regardless of success, because
336      * the memory that does get realloc'd may change
337      * the bounds values of this block
338      */
339     vpx_memory_tracker_remove((size_t)memblk);
340
341 #if TRY_BOUNDS_CHECK
342     {
343         int i;
344         unsigned int tempme = BOUNDS_CHECK_VALUE;
345
346         x_bounds = vpx_realloc(memblk, size + (BOUNDS_CHECK_PAD_SIZE * 2));
347
348         if (x_bounds)
349         {
350             x_bounds = (unsigned char *)(((size_t *)x_bounds)[-1]);
351             x = align_addr(x_bounds + BOUNDS_CHECK_PAD_SIZE + ADDRESS_STORAGE_SIZE,
352                            (int)DEFAULT_ALIGNMENT);
353             /* save the actual malloc address */
354             ((size_t *)x)[-1] = (size_t)x_bounds;
355
356             for (i = 0; i < BOUNDS_CHECK_PAD_SIZE; i += sizeof(unsigned int))
357             {
358                 VPX_MEMCPY_L(x_bounds + i, &tempme, sizeof(unsigned int));
359                 VPX_MEMCPY_L((unsigned char *)x + size + i,
360                              &tempme, sizeof(unsigned int));
361             }
362         }
363         else
364             x = NULL;
365     }
366 #else
367     x = vpx_realloc(memblk, size);
368 #endif /*TRY_BOUNDS_CHECK*/
369
370     if (!memblk) ++g_alloc_count;
371
372     if (x)
373         vpx_memory_tracker_add((size_t)x, (unsigned int)size, file, line, 1);
374     else
375         vpx_memory_tracker_add((size_t)memblk, orig_size, orig_file, orig_line, 1);
376
377     return x;
378 }
379
380 void xvpx_free(void *p_address, char *file, int line)
381 {
382 #if TRY_BOUNDS_CHECK
383     unsigned char *p_bounds_address = (unsigned char *)p_address;
384     /*p_bounds_address -= BOUNDS_CHECK_PAD_SIZE;*/
385 #endif
386
387 #if !TRY_BOUNDS_CHECK_ON_FREE
388     (void)file;
389     (void)line;
390 #endif
391
392     if (p_address)
393     {
394 #if TRY_BOUNDS_CHECK_ON_FREE
395         vpx_memory_tracker_check_integrity(file, line);
396 #endif
397
398         /* if the addr isn't found in the list, assume it was allocated via
399          * vpx_ calls not xvpx_, therefore it does not contain any padding
400          */
401         if (vpx_memory_tracker_remove((size_t)p_address) == -2)
402         {
403             p_bounds_address = p_address;
404             _P(fprintf(stderr, "[vpx_mem][xvpx_free] addr: %p not found in"
405                        " list; freed from file:%s"
406                        " line:%d\n", p_address, file, line));
407         }
408         else
409             --g_alloc_count;
410
411 #if TRY_BOUNDS_CHECK
412         vpx_free(p_bounds_address);
413 #else
414         vpx_free(p_address);
415 #endif
416
417         if (!g_alloc_count)
418             vpx_memory_tracker_destroy();
419     }
420 }
421
422 #endif /*CONFIG_MEM_TRACKER*/
423
424 #if CONFIG_MEM_CHECKS
425 #if defined(VXWORKS)
426 #include <task_lib.h> /*for task_delay()*/
427 /* This function is only used to get a stack trace of the player
428 object so we can se where we are having a problem. */
429 static int get_my_tt(int task)
430 {
431     tt(task);
432
433     return 0;
434 }
435
436 static void vx_sleep(int msec)
437 {
438     int ticks_to_sleep = 0;
439
440     if (msec)
441     {
442         int msec_per_tick = 1000 / sys_clk_rate_get();
443
444         if (msec < msec_per_tick)
445             ticks_to_sleep++;
446         else
447             ticks_to_sleep = msec / msec_per_tick;
448     }
449
450     task_delay(ticks_to_sleep);
451 }
452 #endif
453 #endif
454
455 void *vpx_memcpy(void *dest, const void *source, size_t length)
456 {
457 #if CONFIG_MEM_CHECKS
458
459     if (((int)dest < 0x4000) || ((int)source < 0x4000))
460     {
461         _P(printf("WARNING: vpx_memcpy dest:0x%x source:0x%x len:%d\n", (int)dest, (int)source, length);)
462
463 #if defined(VXWORKS)
464         sp(get_my_tt, task_id_self(), 0, 0, 0, 0, 0, 0, 0, 0);
465
466         vx_sleep(10000);
467 #endif
468     }
469
470 #endif
471
472     return VPX_MEMCPY_L(dest, source, length);
473 }
474
475 void *vpx_memset(void *dest, int val, size_t length)
476 {
477 #if CONFIG_MEM_CHECKS
478
479     if ((int)dest < 0x4000)
480     {
481         _P(printf("WARNING: vpx_memset dest:0x%x val:%d len:%d\n", (int)dest, val, length);)
482
483 #if defined(VXWORKS)
484         sp(get_my_tt, task_id_self(), 0, 0, 0, 0, 0, 0, 0, 0);
485
486         vx_sleep(10000);
487 #endif
488     }
489
490 #endif
491
492     return VPX_MEMSET_L(dest, val, length);
493 }
494
495 void *vpx_memmove(void *dest, const void *src, size_t count)
496 {
497 #if CONFIG_MEM_CHECKS
498
499     if (((int)dest < 0x4000) || ((int)src < 0x4000))
500     {
501         _P(printf("WARNING: vpx_memmove dest:0x%x src:0x%x count:%d\n", (int)dest, (int)src, count);)
502
503 #if defined(VXWORKS)
504         sp(get_my_tt, task_id_self(), 0, 0, 0, 0, 0, 0, 0, 0);
505
506         vx_sleep(10000);
507 #endif
508     }
509
510 #endif
511
512     return VPX_MEMMOVE_L(dest, src, count);
513 }
514
515 #if CONFIG_MEM_MANAGER
516
517 static int vpx_mm_create_heap_memory()
518 {
519     int i_rv = 0;
520
521     if (!g_mng_memory_allocated)
522     {
523 #if MM_DYNAMIC_MEMORY
524         g_p_mng_memory_raw =
525             (unsigned char *)malloc(g_mm_memory_size + HMM_ADDR_ALIGN_UNIT);
526
527         if (g_p_mng_memory_raw)
528         {
529             g_p_mng_memory = (unsigned char *)((((unsigned int)g_p_mng_memory_raw) +
530                                                 HMM_ADDR_ALIGN_UNIT - 1) &
531                                                -(int)HMM_ADDR_ALIGN_UNIT);
532
533             _P(printf("[vpx][mm] total memory size:%d g_p_mng_memory_raw:0x%x g_p_mng_memory:0x%x\n"
534                       , g_mm_memory_size + HMM_ADDR_ALIGN_UNIT
535                       , (unsigned int)g_p_mng_memory_raw
536                       , (unsigned int)g_p_mng_memory);)
537         }
538         else
539         {
540             _P(printf("[vpx][mm] Couldn't allocate memory:%d for vpx memory manager.\n"
541                       , g_mm_memory_size);)
542
543             i_rv = -1;
544         }
545
546         if (g_p_mng_memory)
547 #endif
548         {
549             int chunk_size = 0;
550
551             g_mng_memory_allocated = 1;
552
553             hmm_init(&hmm_d);
554
555             chunk_size = g_mm_memory_size >> SHIFT_HMM_ADDR_ALIGN_UNIT;
556
557             chunk_size -= DUMMY_END_BLOCK_BAUS;
558
559             _P(printf("[vpx][mm] memory size:%d for vpx memory manager. g_p_mng_memory:0x%x  chunk_size:%d\n"
560                       , g_mm_memory_size
561                       , (unsigned int)g_p_mng_memory
562                       , chunk_size);)
563
564             hmm_new_chunk(&hmm_d, (void *)g_p_mng_memory, chunk_size);
565         }
566
567 #if MM_DYNAMIC_MEMORY
568         else
569         {
570             _P(printf("[vpx][mm] Couldn't allocate memory:%d for vpx memory manager.\n"
571                       , g_mm_memory_size);)
572
573             i_rv = -1;
574         }
575
576 #endif
577     }
578
579     return i_rv;
580 }
581
582 static void *vpx_mm_realloc(void *memblk, size_t size)
583 {
584     void *p_ret = NULL;
585
586     if (vpx_mm_create_heap_memory() < 0)
587     {
588         _P(printf("[vpx][mm] ERROR vpx_mm_realloc() Couldn't create memory for Heap.\n");)
589     }
590     else
591     {
592         int i_rv = 0;
593         int old_num_aaus;
594         int new_num_aaus;
595
596         old_num_aaus = hmm_true_size(memblk);
597         new_num_aaus = (size >> SHIFT_HMM_ADDR_ALIGN_UNIT) + 1;
598
599         if (old_num_aaus == new_num_aaus)
600         {
601             p_ret = memblk;
602         }
603         else
604         {
605             i_rv = hmm_resize(&hmm_d, memblk, new_num_aaus);
606
607             if (i_rv == 0)
608             {
609                 p_ret = memblk;
610             }
611             else
612             {
613                 /* Error. Try to malloc and then copy data. */
614                 void *p_from_malloc;
615
616                 new_num_aaus = (size >> SHIFT_HMM_ADDR_ALIGN_UNIT) + 1;
617                 p_from_malloc  = hmm_alloc(&hmm_d, new_num_aaus);
618
619                 if (p_from_malloc)
620                 {
621                     vpx_memcpy(p_from_malloc, memblk, size);
622                     hmm_free(&hmm_d, memblk);
623
624                     p_ret = p_from_malloc;
625                 }
626             }
627         }
628     }
629
630     return p_ret;
631 }
632 #endif /*CONFIG_MEM_MANAGER*/
633
634 #if USE_GLOBAL_FUNCTION_POINTERS
635 # if CONFIG_MEM_TRACKER
636 extern int vpx_memory_tracker_set_functions(g_malloc_func g_malloc_l
637         , g_calloc_func g_calloc_l
638         , g_realloc_func g_realloc_l
639         , g_free_func g_free_l
640         , g_memcpy_func g_memcpy_l
641         , g_memset_func g_memset_l
642         , g_memmove_func g_memmove_l);
643 # endif
644 #endif /*USE_GLOBAL_FUNCTION_POINTERS*/
645 int vpx_mem_set_functions(g_malloc_func g_malloc_l
646                           , g_calloc_func g_calloc_l
647                           , g_realloc_func g_realloc_l
648                           , g_free_func g_free_l
649                           , g_memcpy_func g_memcpy_l
650                           , g_memset_func g_memset_l
651                           , g_memmove_func g_memmove_l)
652 {
653 #if USE_GLOBAL_FUNCTION_POINTERS
654
655     /* If use global functions is turned on then the
656     application must set the global functions before
657     it does anything else or vpx_mem will have
658     unpredictable results. */
659     if (!g_func)
660     {
661         g_func = (struct GLOBAL_FUNC_POINTERS *)
662                  g_malloc_l(sizeof(struct GLOBAL_FUNC_POINTERS));
663
664         if (!g_func)
665         {
666             return -1;
667         }
668     }
669
670 #if CONFIG_MEM_TRACKER
671     {
672         int rv = 0;
673         rv = vpx_memory_tracker_set_functions(g_malloc_l
674                                               , g_calloc_l
675                                               , g_realloc_l
676                                               , g_free_l
677                                               , g_memcpy_l
678                                               , g_memset_l
679                                               , g_memmove_l);
680
681         if (rv < 0)
682         {
683             return rv;
684         }
685     }
686 #endif
687
688     g_func->g_malloc  = g_malloc_l;
689     g_func->g_calloc  = g_calloc_l;
690     g_func->g_realloc = g_realloc_l;
691     g_func->g_free    = g_free_l;
692     g_func->g_memcpy  = g_memcpy_l;
693     g_func->g_memset  = g_memset_l;
694     g_func->g_memmove = g_memmove_l;
695
696     return 0;
697 #else
698     (void)g_malloc_l;
699     (void)g_calloc_l;
700     (void)g_realloc_l;
701     (void)g_free_l;
702     (void)g_memcpy_l;
703     (void)g_memset_l;
704     (void)g_memmove_l;
705     return -1;
706 #endif
707 }
708
709 int vpx_mem_unset_functions()
710 {
711 #if USE_GLOBAL_FUNCTION_POINTERS
712
713     if (g_func)
714     {
715         g_free_func temp_free = g_func->g_free;
716         temp_free(g_func);
717         g_func = NULL;
718     }
719
720 #endif
721     return 0;
722 }