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