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