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