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