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 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 79 unsigned 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 87 int 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 109 void *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 137 void *vpx_malloc(size_t size) { 138 return vpx_memalign(DEFAULT_ALIGNMENT, size); 139 } 140 141 void *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 152 void *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 192 void 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 204 void *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 260 void *xvpx_malloc(size_t size, char *file, int line) { 261 return xvpx_memalign(DEFAULT_ALIGNMENT, size, file, line); 262 } 263 264 void *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 273 void *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 351 void 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 395 object so we can se where we are having a problem. */ 396 static int get_my_tt(int task) { 397 tt(task); 398 399 return 0; 400 } 401 402 static 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 419 void *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 437 void *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 455 void *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 475 static 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 534 static 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 577 extern 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*/ 586 int 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 646 int 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