2 * Copyright (c) 2010 The WebM project authors. All Rights Reserved.
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.
18 #include "include/vpx_mem_intrnl.h"
19 #include "vpx/vpx_integer.h"
21 #if CONFIG_MEM_TRACKER
22 #ifndef VPX_NO_GLOBALS
23 static unsigned long g_alloc_count = 0;
25 #include "vpx_global_handling.h"
26 #define g_alloc_count vpxglobalm(vpxmem,g_alloc_count)
30 #if CONFIG_MEM_MANAGER
32 # include "hmm_intrnl.h"
34 # define SHIFT_HMM_ADDR_ALIGN_UNIT 5
35 # define TOTAL_MEMORY_TO_ALLOCATE 20971520 /* 20 * 1024 * 1024 */
37 # define MM_DYNAMIC_MEMORY 1
38 # if MM_DYNAMIC_MEMORY
39 static unsigned char *g_p_mng_memory_raw = NULL;
40 static unsigned char *g_p_mng_memory = NULL;
42 static unsigned char g_p_mng_memory[TOTAL_MEMORY_TO_ALLOCATE];
45 static size_t g_mm_memory_size = TOTAL_MEMORY_TO_ALLOCATE;
47 static hmm_descriptor hmm_d;
48 static int g_mng_memory_allocated = 0;
50 static int vpx_mm_create_heap_memory();
51 static void *vpx_mm_realloc(void *memblk, size_t size);
52 #endif /*CONFIG_MEM_MANAGER*/
54 #if USE_GLOBAL_FUNCTION_POINTERS
55 struct GLOBAL_FUNC_POINTERS {
56 g_malloc_func g_malloc;
57 g_calloc_func g_calloc;
58 g_realloc_func g_realloc;
60 g_memcpy_func g_memcpy;
61 g_memset_func g_memset;
62 g_memmove_func g_memmove;
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
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 */
80 unsigned 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);
88 int vpx_mem_set_heap_size(size_t size) {
91 #if CONFIG_MEM_MANAGER
94 if (!g_mng_memory_allocated && size) {
95 g_mm_memory_size = size;
110 void *vpx_memalign(size_t align, size_t size) {
114 #if CONFIG_MEM_MANAGER
117 if (vpx_mm_create_heap_memory() < 0) {
118 _P(printf("[vpx][mm] ERROR vpx_memalign() Couldn't create memory for Heap.\n");)
121 number_aau = ((size + align - 1 + ADDRESS_STORAGE_SIZE) >>
122 SHIFT_HMM_ADDR_ALIGN_UNIT) + 1;
124 addr = hmm_alloc(&hmm_d, number_aau);
126 addr = VPX_MALLOC_L(size + align - 1 + ADDRESS_STORAGE_SIZE);
127 #endif /*CONFIG_MEM_MANAGER*/
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;
138 void *vpx_malloc(size_t size) {
139 return vpx_memalign(DEFAULT_ALIGNMENT, size);
142 void *vpx_calloc(size_t num, size_t size) {
145 x = vpx_memalign(DEFAULT_ALIGNMENT, num * size);
148 VPX_MEMSET_L(x, 0, num * size);
153 void *vpx_realloc(void *memblk, size_t size) {
156 int align = DEFAULT_ALIGNMENT;
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.
167 new_addr = vpx_malloc(size);
171 addr = (void *)(((size_t *)memblk)[-1]);
174 #if CONFIG_MEM_MANAGER
175 new_addr = vpx_mm_realloc(addr, size + align + ADDRESS_STORAGE_SIZE);
177 new_addr = VPX_REALLOC_L(addr, size + align + ADDRESS_STORAGE_SIZE);
182 new_addr = (void *)(((size_t)
183 ((unsigned char *)new_addr + ADDRESS_STORAGE_SIZE) + (align - 1)) &
185 /* save the actual malloc address */
186 ((size_t *)new_addr)[-1] = (size_t)addr;
193 void vpx_free(void *memblk) {
195 void *addr = (void *)(((size_t *)memblk)[-1]);
196 #if CONFIG_MEM_MANAGER
197 hmm_free(&hmm_d, addr);
204 #if CONFIG_MEM_TRACKER
205 void *xvpx_memalign(size_t align, size_t size, char *file, int line) {
207 unsigned char *x_bounds;
212 if (g_alloc_count == 0) {
214 int i_rv = vpx_memory_tracker_init(BOUNDS_CHECK_PAD_SIZE, BOUNDS_CHECK_VALUE);
216 int i_rv = vpx_memory_tracker_init(0, 0);
220 _P(printf("ERROR xvpx_malloc MEM_TRACK_USAGE error vpx_memory_tracker_init().\n");)
227 unsigned int tempme = BOUNDS_CHECK_VALUE;
229 x_bounds = vpx_memalign(align, size + (BOUNDS_CHECK_PAD_SIZE * 2));
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,
239 /* save the actual malloc address */
240 ((size_t *)x)[-1] = (size_t)x_bounds;
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));
251 x = vpx_memalign(align, size);
252 #endif /*TRY_BOUNDS_CHECK*/
256 vpx_memory_tracker_add((size_t)x, (unsigned int)size, file, line, 1);
261 void *xvpx_malloc(size_t size, char *file, int line) {
262 return xvpx_memalign(DEFAULT_ALIGNMENT, size, file, line);
265 void *xvpx_calloc(size_t num, size_t size, char *file, int line) {
266 void *x = xvpx_memalign(DEFAULT_ALIGNMENT, num * size, file, line);
269 VPX_MEMSET_L(x, 0, num * size);
274 void *xvpx_realloc(void *memblk, size_t size, char *file, int line) {
275 struct mem_block *p = NULL;
278 char *orig_file = NULL;
281 unsigned char *x_bounds = memblk ?
282 (unsigned char *)(((size_t *)memblk)[-1]) :
288 if (g_alloc_count == 0) {
291 if (!vpx_memory_tracker_init(BOUNDS_CHECK_PAD_SIZE, BOUNDS_CHECK_VALUE))
293 if (!vpx_memory_tracker_init(0, 0))
296 _P(printf("ERROR xvpx_malloc MEM_TRACK_USAGE error vpx_memory_tracker_init().\n");)
300 if ((p = vpx_memory_tracker_find((size_t)memblk))) {
306 #if TRY_BOUNDS_CHECK_ON_FREE
307 vpx_memory_tracker_check_integrity(file, line);
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
314 vpx_memory_tracker_remove((size_t)memblk);
319 unsigned int tempme = BOUNDS_CHECK_VALUE;
321 x_bounds = vpx_realloc(memblk, size + (BOUNDS_CHECK_PAD_SIZE * 2));
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;
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));
339 x = vpx_realloc(memblk, size);
340 #endif /*TRY_BOUNDS_CHECK*/
342 if (!memblk) ++g_alloc_count;
345 vpx_memory_tracker_add((size_t)x, (unsigned int)size, file, line, 1);
347 vpx_memory_tracker_add((size_t)memblk, orig_size, orig_file, orig_line, 1);
352 void xvpx_free(void *p_address, char *file, int line) {
354 unsigned char *p_bounds_address = (unsigned char *)p_address;
355 /*p_bounds_address -= BOUNDS_CHECK_PAD_SIZE;*/
358 #if !TRY_BOUNDS_CHECK_ON_FREE
364 #if TRY_BOUNDS_CHECK_ON_FREE
365 vpx_memory_tracker_check_integrity(file, line);
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
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));
380 vpx_free(p_bounds_address);
386 vpx_memory_tracker_destroy();
390 #endif /*CONFIG_MEM_TRACKER*/
392 #if CONFIG_MEM_CHECKS
394 #include <task_lib.h> /*for task_delay()*/
395 /* This function is only used to get a stack trace of the player
396 object so we can se where we are having a problem. */
397 static int get_my_tt(int task) {
403 static void vx_sleep(int msec) {
404 int ticks_to_sleep = 0;
407 int msec_per_tick = 1000 / sys_clk_rate_get();
409 if (msec < msec_per_tick)
412 ticks_to_sleep = msec / msec_per_tick;
415 task_delay(ticks_to_sleep);
420 void *vpx_memcpy(void *dest, const void *source, size_t length) {
421 #if CONFIG_MEM_CHECKS
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);)
427 sp(get_my_tt, task_id_self(), 0, 0, 0, 0, 0, 0, 0, 0);
435 return VPX_MEMCPY_L(dest, source, length);
438 void *vpx_memset(void *dest, int val, size_t length) {
439 #if CONFIG_MEM_CHECKS
441 if ((int)dest < 0x4000) {
442 _P(printf("WARNING: vpx_memset dest:0x%x val:%d len:%d\n", (int)dest, val, length);)
445 sp(get_my_tt, task_id_self(), 0, 0, 0, 0, 0, 0, 0, 0);
453 return VPX_MEMSET_L(dest, val, length);
456 #if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
457 void *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);)
464 sp(get_my_tt, task_id_self(), 0, 0, 0, 0, 0, 0, 0, 0);
472 uint16_t *dest16 = dest;
473 for (i = 0; i < length; i++)
477 #endif // CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
479 void *vpx_memmove(void *dest, const void *src, size_t count) {
480 #if CONFIG_MEM_CHECKS
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);)
486 sp(get_my_tt, task_id_self(), 0, 0, 0, 0, 0, 0, 0, 0);
494 return VPX_MEMMOVE_L(dest, src, count);
497 #if CONFIG_MEM_MANAGER
499 static int vpx_mm_create_heap_memory() {
502 if (!g_mng_memory_allocated) {
503 #if MM_DYNAMIC_MEMORY
505 (unsigned char *)malloc(g_mm_memory_size + HMM_ADDR_ALIGN_UNIT);
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);
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);)
517 _P(printf("[vpx][mm] Couldn't allocate memory:%d for vpx memory manager.\n"
518 , g_mm_memory_size);)
528 g_mng_memory_allocated = 1;
532 chunk_size = g_mm_memory_size >> SHIFT_HMM_ADDR_ALIGN_UNIT;
534 chunk_size -= DUMMY_END_BLOCK_BAUS;
536 _P(printf("[vpx][mm] memory size:%d for vpx memory manager. g_p_mng_memory:0x%x chunk_size:%d\n"
538 , (unsigned int)g_p_mng_memory
541 hmm_new_chunk(&hmm_d, (void *)g_p_mng_memory, chunk_size);
544 #if MM_DYNAMIC_MEMORY
546 _P(printf("[vpx][mm] Couldn't allocate memory:%d for vpx memory manager.\n"
547 , g_mm_memory_size);)
558 static void *vpx_mm_realloc(void *memblk, size_t size) {
561 if (vpx_mm_create_heap_memory() < 0) {
562 _P(printf("[vpx][mm] ERROR vpx_mm_realloc() Couldn't create memory for Heap.\n");)
568 old_num_aaus = hmm_true_size(memblk);
569 new_num_aaus = (size >> SHIFT_HMM_ADDR_ALIGN_UNIT) + 1;
571 if (old_num_aaus == new_num_aaus) {
574 i_rv = hmm_resize(&hmm_d, memblk, new_num_aaus);
579 /* Error. Try to malloc and then copy data. */
582 new_num_aaus = (size >> SHIFT_HMM_ADDR_ALIGN_UNIT) + 1;
583 p_from_malloc = hmm_alloc(&hmm_d, new_num_aaus);
586 vpx_memcpy(p_from_malloc, memblk, size);
587 hmm_free(&hmm_d, memblk);
589 p_ret = p_from_malloc;
597 #endif /*CONFIG_MEM_MANAGER*/
599 #if USE_GLOBAL_FUNCTION_POINTERS
600 # if CONFIG_MEM_TRACKER
601 extern 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);
609 #endif /*USE_GLOBAL_FUNCTION_POINTERS*/
610 int 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
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. */
624 g_func = (struct GLOBAL_FUNC_POINTERS *)
625 g_malloc_l(sizeof(struct GLOBAL_FUNC_POINTERS));
632 #if CONFIG_MEM_TRACKER
635 rv = vpx_memory_tracker_set_functions(g_malloc_l
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;
670 int vpx_mem_unset_functions() {
671 #if USE_GLOBAL_FUNCTION_POINTERS
674 g_free_func temp_free = g_func->g_free;