vpx_mem.c revision 1b362b15af34006e6a11974088a46d42b903418e
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
22static 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
38static unsigned char *g_p_mng_memory_raw = NULL;
39static unsigned char *g_p_mng_memory     = NULL;
40# else
41static unsigned char g_p_mng_memory[TOTAL_MEMORY_TO_ALLOCATE];
42# endif
43
44static size_t g_mm_memory_size = TOTAL_MEMORY_TO_ALLOCATE;
45
46static hmm_descriptor hmm_d;
47static int g_mng_memory_allocated = 0;
48
49static int vpx_mm_create_heap_memory();
50static void *vpx_mm_realloc(void *memblk, size_t size);
51#endif /*CONFIG_MEM_MANAGER*/
52
53#if USE_GLOBAL_FUNCTION_POINTERS
54struct 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
80unsigned 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
89int 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
114void *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
145void *vpx_malloc(size_t size)
146{
147    return vpx_memalign(DEFAULT_ALIGNMENT, size);
148}
149
150void *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
162void *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
205void 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
219void *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
281void *xvpx_malloc(size_t size, char *file, int line)
282{
283    return xvpx_memalign(DEFAULT_ALIGNMENT, size, file, line);
284}
285
286void *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
296void *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
380void 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
428object so we can se where we are having a problem. */
429static int get_my_tt(int task)
430{
431    tt(task);
432
433    return 0;
434}
435
436static 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
455void *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
475void *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
495void *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
517static 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
582static 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
636extern 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*/
645int 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
709int 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}
723