Home | History | Annotate | Download | only in intel_linux
      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 /*
     13   vpx_mem_tracker.c
     14 
     15   jwz 2003-09-30:
     16    Stores a list of addreses, their size, and file and line they came from.
     17    All exposed lib functions are prefaced by vpx_ and allow the global list
     18    to be thread safe.
     19    Current supported platforms are:
     20     Linux, Win32, win_ce and vx_works
     21    Further support can be added by defining the platform specific mutex
     22    in the memory_tracker struct as well as calls to create/destroy/lock/unlock
     23    the mutex in vpx_memory_tracker_init/Destroy and memory_tracker_lock_mutex/unlock_mutex
     24 */
     25 
     26 #define NO_MUTEX
     27 
     28 #if defined(__uClinux__)
     29 # include <lddk.h>
     30 #endif
     31 
     32 #if defined(LINUX) || defined(__uClinux__)
     33 # include <pthread.h>
     34 #elif defined(WIN32) || defined(_WIN32_WCE)
     35 # define WIN32_LEAN_AND_MEAN
     36 # include <windows.h>
     37 # include <winbase.h>
     38 #elif defined(VXWORKS)
     39 # include <sem_lib.h>
     40 #elif defined(NDS_NITRO)
     41 # include <nitro.h>
     42 # include <nitro/os.h>
     43 #endif
     44 
     45 #include <stdio.h>
     46 #include <stdlib.h>
     47 #include <string.h> //VXWORKS doesn't have a malloc/memory.h file,
     48 //this should pull in malloc,free,etc.
     49 #include <stdarg.h>
     50 
     51 #include "vpx_mem_tracker.h"
     52 
     53 #undef vpx_malloc   //undefine any vpx_mem macros that may affect calls to
     54 #undef vpx_free     //memory functions in this file
     55 #undef vpx_memcpy
     56 #undef vpx_memset
     57 
     58 
     59 #ifndef USE_GLOBAL_FUNCTION_POINTERS
     60 # define USE_GLOBAL_FUNCTION_POINTERS   0  //use function pointers instead of compiled functions.
     61 #endif
     62 
     63 #if USE_GLOBAL_FUNCTION_POINTERS
     64 static mem_track_malloc_func g_malloc   = malloc;
     65 static mem_track_calloc_func g_calloc   = calloc;
     66 static mem_track_realloc_func g_realloc = realloc;
     67 static mem_track_free_func g_free       = free;
     68 static mem_track_memcpy_func g_memcpy   = memcpy;
     69 static mem_track_memset_func g_memset   = memset;
     70 static mem_track_memmove_func g_memmove = memmove;
     71 # define MEM_TRACK_MALLOC g_malloc
     72 # define MEM_TRACK_FREE   g_free
     73 # define MEM_TRACK_MEMCPY g_memcpy
     74 # define MEM_TRACK_MEMSET g_memset
     75 #else
     76 # define MEM_TRACK_MALLOC vpx_malloc
     77 # define MEM_TRACK_FREE   vpx_free
     78 # define MEM_TRACK_MEMCPY vpx_memcpy
     79 # define MEM_TRACK_MEMSET vpx_memset
     80 #endif // USE_GLOBAL_FUNCTION_POINTERS
     81 
     82 
     83 struct memory_tracker
     84 {
     85     struct mem_block *head,
     86             * tail;
     87     int len,
     88         totalsize;
     89     unsigned int current_allocated,
     90              max_allocated;
     91 
     92 #if defined(LINUX) || defined(__uClinux__)
     93     pthread_mutex_t mutex;
     94 #elif defined(WIN32) || defined(_WIN32_WCE)
     95     HANDLE mutex;
     96 #elif defined(VXWORKS)
     97     SEM_ID mutex;
     98 #elif defined(NDS_NITRO)
     99     OSMutex mutex;
    100 #elif defined(NO_MUTEX)
    101 #else
    102 #error "No mutex type defined for this platform!"
    103 #endif
    104 
    105     int padding_size,
    106         pad_value;
    107 };
    108 
    109 /* prototypes for internal library functions */
    110 static void memtrack_log(const char *fmt, ...);
    111 static void memory_tracker_dump();
    112 static void memory_tracker_check_integrity(char *file, unsigned int line);
    113 static void memory_tracker_add(size_t addr, unsigned int size,
    114                                char *file, unsigned int line,
    115                                int padded);
    116 static int memory_tracker_remove(size_t addr);
    117 static struct mem_block *memory_tracker_find(size_t addr);
    118 
    119 #if defined(NO_MUTEX)
    120 # define memory_tracker_lock_mutex() (!g_b_mem_tracker_inited)
    121 # define memory_tracker_unlock_mutex()
    122 #else
    123 static int memory_tracker_lock_mutex();
    124 static int memory_tracker_unlock_mutex();
    125 #endif
    126 
    127 static struct memory_tracker memtrack;   //our global memory allocation list
    128 static int g_b_mem_tracker_inited = 0;     //indicates whether the global list has
    129 //been initialized (1:yes/0:no)
    130 static struct
    131 {
    132     FILE *file;
    133     int type;
    134     void (*func)(void *userdata, const char *fmt, va_list args);
    135     void *userdata;
    136 } g_logging = {0};
    137 
    138 extern void *vpx_malloc(size_t size);
    139 extern void vpx_free(void *memblk);
    140 extern void *vpx_memcpy(void *dest, const void *src, size_t length);
    141 extern void *vpx_memset(void *dest, int val, size_t length);
    142 
    143 /*
    144  *
    145  * Exposed library functions
    146  *
    147 */
    148 
    149 /*
    150     vpx_memory_tracker_init(int padding_size, int pad_value)
    151       padding_size - the size of the padding before and after each mem addr.
    152                      Values > 0 indicate that integrity checks can be performed
    153                      by inspecting these areas.
    154       pad_value - the initial value within the padding area before and after
    155                   each mem addr.
    156 
    157     Initializes global memory tracker structure
    158     Allocates the head of the list
    159 */
    160 int vpx_memory_tracker_init(int padding_size, int pad_value)
    161 {
    162     if (!g_b_mem_tracker_inited)
    163     {
    164         if (memtrack.head = (struct mem_block *)MEM_TRACK_MALLOC(sizeof(struct mem_block)))
    165         {
    166             int ret;
    167 
    168             MEM_TRACK_MEMSET(memtrack.head, 0, sizeof(struct mem_block));
    169 
    170             memtrack.tail = memtrack.head;
    171 
    172             memtrack.current_allocated = 0;
    173             memtrack.max_allocated     = 0;
    174 
    175             memtrack.padding_size = padding_size;
    176             memtrack.pad_value    = pad_value;
    177 
    178 #if defined(LINUX) || defined(__uClinux__)
    179             ret = pthread_mutex_init(&memtrack.mutex,
    180                                      NULL);            /*mutex attributes (NULL=default)*/
    181 #elif defined(WIN32) || defined(_WIN32_WCE)
    182             memtrack.mutex = create_mutex(NULL,   /*security attributes*/
    183                                           FALSE,  /*we don't want initial ownership*/
    184                                           NULL);  /*mutex name*/
    185             ret = !memtrack.mutex;
    186 #elif defined(VXWORKS)
    187             memtrack.mutex = sem_bcreate(SEM_Q_FIFO, /*SEM_Q_FIFO non-priority based mutex*/
    188                                          SEM_FULL);  /*SEM_FULL initial state is unlocked*/
    189             ret = !memtrack.mutex;
    190 #elif defined(NDS_NITRO)
    191             os_init_mutex(&memtrack.mutex);
    192             ret = 0;
    193 #elif defined(NO_MUTEX)
    194             ret = 0;
    195 #endif
    196 
    197             if (ret)
    198             {
    199                 memtrack_log("vpx_memory_tracker_init: Error creating mutex!\n");
    200 
    201                 MEM_TRACK_FREE(memtrack.head);
    202                 memtrack.head = NULL;
    203             }
    204             else
    205             {
    206                 memtrack_log("Memory Tracker init'd, v."vpx_mem_tracker_version" pad_size:%d pad_val:0x%x %d\n"
    207                              , padding_size
    208                              , pad_value
    209                              , pad_value);
    210                 g_b_mem_tracker_inited = 1;
    211             }
    212         }
    213     }
    214 
    215     return g_b_mem_tracker_inited;
    216 }
    217 
    218 /*
    219     vpx_memory_tracker_destroy()
    220     If our global struct was initialized zeros out all its members,
    221     frees memory and destroys it's mutex
    222 */
    223 void vpx_memory_tracker_destroy()
    224 {
    225 
    226     if (!memory_tracker_lock_mutex())
    227     {
    228         struct mem_block *p  = memtrack.head,
    229                                   * p2 = memtrack.head;
    230 
    231         memory_tracker_dump();
    232 
    233         while (p)
    234     {
    235             p2 = p;
    236             p  = p->next;
    237 
    238             MEM_TRACK_FREE(p2);
    239         }
    240 
    241         memtrack.head              = NULL;
    242         memtrack.tail              = NULL;
    243         memtrack.len               = 0;
    244         memtrack.current_allocated = 0;
    245         memtrack.max_allocated     = 0;
    246 
    247         if ((g_logging.type == 0) && (g_logging.file != 0)) //&& (g_logging.file != stderr) )
    248         {
    249 #if !defined(NDS_NITRO)
    250             fclose(g_logging.file);
    251 #endif
    252             g_logging.file = NULL;
    253         }
    254 
    255         memory_tracker_unlock_mutex();
    256 
    257         g_b_mem_tracker_inited = 0;
    258 
    259     }
    260 
    261 }
    262 
    263 /*
    264     vpx_memory_tracker_add(size_t addr, unsigned int size,
    265                          char * file, unsigned int line)
    266       addr - memory address to be added to list
    267       size - size of addr
    268       file - the file addr was referenced from
    269       line - the line in file addr was referenced from
    270     Adds memory address addr, it's size, file and line it came from
    271     to the global list via the thread safe internal library function
    272 */
    273 void vpx_memory_tracker_add(size_t addr, unsigned int size,
    274                             char *file, unsigned int line,
    275                             int padded)
    276 {
    277     memory_tracker_add(addr, size, file, line, padded);
    278 }
    279 
    280 /*
    281     vpx_memory_tracker_remove(size_t addr)
    282       addr - memory address to be removed from list
    283     Removes addr from the global list via the thread safe
    284     internal remove function
    285     Return:
    286       Same as described for memory_tracker_remove
    287 */
    288 int vpx_memory_tracker_remove(size_t addr)
    289 {
    290     return memory_tracker_remove(addr);
    291 }
    292 
    293 /*
    294     vpx_memory_tracker_find(size_t addr)
    295       addr - address to be found in list
    296     Return:
    297         If found, pointer to the memory block that matches addr
    298         NULL otherwise
    299 */
    300 struct mem_block *vpx_memory_tracker_find(size_t addr)
    301 {
    302     struct mem_block *p = NULL;
    303 
    304     if (!memory_tracker_lock_mutex())
    305     {
    306         p = memory_tracker_find(addr);
    307         memory_tracker_unlock_mutex();
    308     }
    309 
    310     return p;
    311 }
    312 
    313 /*
    314     vpx_memory_tracker_dump()
    315     Locks the memory tracker's mutex and calls the internal
    316     library function to dump the current contents of the
    317     global memory allocation list
    318 */
    319 void vpx_memory_tracker_dump()
    320 {
    321     if (!memory_tracker_lock_mutex())
    322     {
    323         memory_tracker_dump();
    324         memory_tracker_unlock_mutex();
    325     }
    326 }
    327 
    328 /*
    329     vpx_memory_tracker_check_integrity(char* file, unsigned int line)
    330       file - The file name where the check was placed
    331       line - The line in file where the check was placed
    332     Locks the memory tracker's mutex and calls the internal
    333     integrity check function to inspect every address in the global
    334     memory allocation list
    335 */
    336 void vpx_memory_tracker_check_integrity(char *file, unsigned int line)
    337 {
    338     if (!memory_tracker_lock_mutex())
    339     {
    340         memory_tracker_check_integrity(file, line);
    341         memory_tracker_unlock_mutex();
    342     }
    343 }
    344 
    345 /*
    346     vpx_memory_tracker_set_log_type
    347     Sets the logging type for the memory tracker. Based on the value it will
    348     direct its output to the appropriate place.
    349     Return:
    350       0: on success
    351       -1: if the logging type could not be set, because the value was invalid
    352           or because a file could not be opened
    353 */
    354 int vpx_memory_tracker_set_log_type(int type, char *option)
    355 {
    356     int ret = -1;
    357 
    358 
    359     switch (type)
    360     {
    361     case 0:
    362         g_logging.type = 0;
    363 
    364         if (!option)
    365         {
    366             // g_logging.file = stderr;
    367             ret = 0;
    368         }
    369 
    370 #if !defined(NDS_NITRO)
    371         else
    372         {
    373             if (g_logging.file = fopen((char *)option, "w"))
    374                 ret = 0;
    375         }
    376 
    377 #endif
    378         break;
    379 #if defined(WIN32) && !defined(_WIN32_WCE)
    380     case 1:
    381         g_logging.type = type;
    382         ret = 0;
    383         break;
    384 #endif
    385     default:
    386         break;
    387     }
    388 
    389     //output the version to the new logging destination
    390     if (!ret)
    391         memtrack_log("Memory Tracker logging initialized, "
    392                      "Memory Tracker v."vpx_mem_tracker_version"\n");
    393 
    394     return ret;
    395 }
    396 
    397 /*
    398     vpx_memory_tracker_set_log_func
    399     Sets a logging function to be used by the memory tracker.
    400     Return:
    401       0: on success
    402       -1: if the logging type could not be set because logfunc was NULL
    403 */
    404 int vpx_memory_tracker_set_log_func(void *userdata,
    405                                     void(*logfunc)(void *userdata,
    406                                             const char *fmt, va_list args))
    407 {
    408     int ret = -1;
    409 
    410     if (logfunc)
    411     {
    412         g_logging.type     = -1;
    413         g_logging.userdata = userdata;
    414         g_logging.func     = logfunc;
    415         ret = 0;
    416     }
    417 
    418     //output the version to the new logging destination
    419     if (!ret)
    420         memtrack_log("Memory Tracker logging initialized, "
    421                      "Memory Tracker v."vpx_mem_tracker_version"\n");
    422 
    423     return ret;
    424 }
    425 
    426 /*
    427  *
    428  * END - Exposed library functions
    429  *
    430 */
    431 
    432 
    433 /*
    434  *
    435  * Internal library functions
    436  *
    437 */
    438 
    439 static void memtrack_log(const char *fmt, ...)
    440 {
    441     va_list list;
    442 
    443     va_start(list, fmt);
    444 
    445     switch (g_logging.type)
    446     {
    447     case -1:
    448 
    449         if (g_logging.func)
    450             g_logging.func(g_logging.userdata, fmt, list);
    451 
    452         break;
    453     case 0:
    454 
    455         if (g_logging.file)
    456         {
    457             vfprintf(g_logging.file, fmt, list);
    458             fflush(g_logging.file);
    459         }
    460 
    461         break;
    462 #if defined(WIN32) && !defined(_WIN32_WCE)
    463     case 1:
    464     {
    465         char temp[1024];
    466         _vsnprintf(temp, sizeof(temp) / sizeof(char) - 1, fmt, list);
    467         output_debug_string(temp);
    468     }
    469     break;
    470 #endif
    471     default:
    472         break;
    473     }
    474 
    475     va_end(list);
    476 }
    477 
    478 /*
    479     memory_tracker_dump()
    480     Dumps the current contents of the global memory allocation list
    481 */
    482 static void memory_tracker_dump()
    483 {
    484     int i = 0;
    485     struct mem_block *p = (memtrack.head ? memtrack.head->next : NULL);
    486 
    487     memtrack_log("\n_currently Allocated= %d; Max allocated= %d\n",
    488                  memtrack.current_allocated, memtrack.max_allocated);
    489 
    490     while (p)
    491     {
    492 #if defined(WIN32) && !defined(_WIN32_WCE)
    493 
    494         /*when using outputdebugstring, output filenames so they
    495           can be clicked to be opened in visual studio*/
    496         if (g_logging.type == 1)
    497             memtrack_log("memblocks[%d].addr= 0x%.8x, memblocks[%d].size= %d, file:\n"
    498                          "  %s(%d):\n", i,
    499                          p->addr, i, p->size,
    500                          p->file, p->line);
    501         else
    502 #endif
    503             memtrack_log("memblocks[%d].addr= 0x%.8x, memblocks[%d].size= %d, file: %s, line: %d\n", i,
    504                          p->addr, i, p->size,
    505                          p->file, p->line);
    506 
    507         p = p->next;
    508         ++i;
    509     }
    510 
    511     memtrack_log("\n");
    512 }
    513 
    514 /*
    515     memory_tracker_check_integrity(char* file, unsigned int file)
    516       file - the file name where the check was placed
    517       line - the line in file where the check was placed
    518     If a padding_size was supplied to vpx_memory_tracker_init()
    519     this function will check ea. addr in the list verifying that
    520     addr-padding_size and addr+padding_size is filled with pad_value
    521 */
    522 static void memory_tracker_check_integrity(char *file, unsigned int line)
    523 {
    524     if (memtrack.padding_size)
    525     {
    526         int i,
    527             index = 0;
    528         unsigned char *p_show_me,
    529                  * p_show_me2;
    530         unsigned int tempme = memtrack.pad_value,
    531                      dead1,
    532                      dead2;
    533         unsigned char *x_bounds;
    534         struct mem_block *p = memtrack.head->next;
    535 
    536         while (p)
    537         {
    538             //x_bounds = (unsigned char*)p->addr;
    539             //back up VPX_BYTE_ALIGNMENT
    540             //x_bounds -= memtrack.padding_size;
    541 
    542             if (p->padded)   // can the bounds be checked?
    543             {
    544                 /*yes, move to the address that was actually allocated
    545                 by the vpx_* calls*/
    546                 x_bounds = (unsigned char *)(((size_t *)p->addr)[-1]);
    547 
    548                 for (i = 0; i < memtrack.padding_size; i += sizeof(unsigned int))
    549                 {
    550                     p_show_me = (x_bounds + i);
    551                     p_show_me2 = (unsigned char *)(p->addr + p->size + i);
    552 
    553                     MEM_TRACK_MEMCPY(&dead1, p_show_me, sizeof(unsigned int));
    554                     MEM_TRACK_MEMCPY(&dead2, p_show_me2, sizeof(unsigned int));
    555 
    556                     if ((dead1 != tempme) || (dead2 != tempme))
    557                     {
    558                         memtrack_log("\n[vpx_mem integrity check failed]:\n"
    559                                      "    index[%d] {%s:%d} addr=0x%x, size=%d,"
    560                                      " file: %s, line: %d c0:0x%x c1:0x%x\n",
    561                                      index, file, line, p->addr, p->size, p->file,
    562                                      p->line, dead1, dead2);
    563                     }
    564                 }
    565             }
    566 
    567             ++index;
    568             p = p->next;
    569         }
    570     }
    571 }
    572 
    573 /*
    574     memory_tracker_add(size_t addr, unsigned int size,
    575                      char * file, unsigned int line)
    576     Adds an address (addr), it's size, file and line number to our list.
    577     Adjusts the total bytes allocated and max bytes allocated if necessary.
    578     If memory cannot be allocated the list will be destroyed.
    579 */
    580 void memory_tracker_add(size_t addr, unsigned int size,
    581                         char *file, unsigned int line,
    582                         int padded)
    583 {
    584     if (!memory_tracker_lock_mutex())
    585     {
    586         struct mem_block *p;
    587 
    588         p = MEM_TRACK_MALLOC(sizeof(struct mem_block));
    589 
    590         if (p)
    591         {
    592             p->prev       = memtrack.tail;
    593             p->prev->next = p;
    594             p->addr       = addr;
    595             p->size       = size;
    596             p->line       = line;
    597             p->file       = file;
    598             p->padded     = padded;
    599             p->next       = NULL;
    600 
    601             memtrack.tail = p;
    602 
    603             memtrack.current_allocated += size;
    604 
    605             if (memtrack.current_allocated > memtrack.max_allocated)
    606                 memtrack.max_allocated = memtrack.current_allocated;
    607 
    608             //memtrack_log("memory_tracker_add: added addr=0x%.8x\n", addr);
    609 
    610             memory_tracker_unlock_mutex();
    611         }
    612         else
    613         {
    614             memtrack_log("memory_tracker_add: error allocating memory!\n");
    615             memory_tracker_unlock_mutex();
    616             vpx_memory_tracker_destroy();
    617         }
    618     }
    619 }
    620 
    621 /*
    622     memory_tracker_remove(size_t addr)
    623     Removes an address and its corresponding size (if they exist)
    624     from the memory tracker list and adjusts the current number
    625     of bytes allocated.
    626     Return:
    627       0: on success
    628       -1: if the mutex could not be locked
    629       -2: if the addr was not found in the list
    630 */
    631 int memory_tracker_remove(size_t addr)
    632 {
    633     int ret = -1;
    634 
    635     if (!memory_tracker_lock_mutex())
    636     {
    637         struct mem_block *p;
    638 
    639         if (p = memory_tracker_find(addr))
    640         {
    641             memtrack.current_allocated -= p->size;
    642 
    643             p->prev->next = p->next;
    644 
    645             if (p->next)
    646                 p->next->prev = p->prev;
    647             else
    648                 memtrack.tail = p->prev;
    649 
    650             ret = 0;
    651             MEM_TRACK_FREE(p);
    652         }
    653         else
    654         {
    655             memtrack_log("memory_tracker_remove(): addr not found in list, 0x%.8x\n", addr);
    656             ret = -2;
    657         }
    658 
    659         memory_tracker_unlock_mutex();
    660     }
    661 
    662     return ret;
    663 }
    664 
    665 /*
    666     memory_tracker_find(size_t addr)
    667     Finds an address in our addrs list
    668     NOTE: the mutex MUST be locked in the other internal
    669           functions before calling this one. This avoids
    670           the need for repeated locking and unlocking as in Remove
    671     Returns: pointer to the mem block if found, NULL otherwise
    672 */
    673 static struct mem_block *memory_tracker_find(size_t addr)
    674 {
    675     struct mem_block *p = NULL;
    676 
    677     if (memtrack.head)
    678     {
    679         p = memtrack.head->next;
    680 
    681         while (p && (p->addr != addr))
    682             p = p->next;
    683     }
    684 
    685     return p;
    686 }
    687 
    688 
    689 #if !defined(NO_MUTEX)
    690 /*
    691     memory_tracker_lock_mutex()
    692     Locks the memory tracker mutex with a platform specific call
    693     Returns:
    694         0: Success
    695        <0: Failure, either the mutex was not initialized
    696            or the call to lock the mutex failed
    697 */
    698 static int memory_tracker_lock_mutex()
    699 {
    700     int ret = -1;
    701 
    702     if (g_b_mem_tracker_inited)
    703     {
    704 
    705 #if defined(LINUX) || defined(__uClinux__)
    706         ret = pthread_mutex_lock(&memtrack.mutex);
    707 #elif defined(WIN32) || defined(_WIN32_WCE)
    708         ret = WaitForSingleObject(memtrack.mutex, INFINITE);
    709 #elif defined(VXWORKS)
    710         ret = sem_take(memtrack.mutex, WAIT_FOREVER);
    711 #elif defined(NDS_NITRO)
    712         os_lock_mutex(&memtrack.mutex);
    713         ret = 0;
    714 #endif
    715 
    716         if (ret)
    717         {
    718             memtrack_log("memory_tracker_lock_mutex: mutex lock failed\n");
    719         }
    720     }
    721 
    722     return ret;
    723 }
    724 
    725 /*
    726     memory_tracker_unlock_mutex()
    727     Unlocks the memory tracker mutex with a platform specific call
    728     Returns:
    729         0: Success
    730        <0: Failure, either the mutex was not initialized
    731            or the call to unlock the mutex failed
    732 */
    733 static int memory_tracker_unlock_mutex()
    734 {
    735     int ret = -1;
    736 
    737     if (g_b_mem_tracker_inited)
    738     {
    739 
    740 #if defined(LINUX) || defined(__uClinux__)
    741         ret = pthread_mutex_unlock(&memtrack.mutex);
    742 #elif defined(WIN32) || defined(_WIN32_WCE)
    743         ret = !release_mutex(memtrack.mutex);
    744 #elif defined(VXWORKS)
    745         ret = sem_give(memtrack.mutex);
    746 #elif defined(NDS_NITRO)
    747         os_unlock_mutex(&memtrack.mutex);
    748         ret = 0;
    749 #endif
    750 
    751         if (ret)
    752         {
    753             memtrack_log("memory_tracker_unlock_mutex: mutex unlock failed\n");
    754         }
    755     }
    756 
    757     return ret;
    758 }
    759 #endif
    760 
    761 /*
    762     vpx_memory_tracker_set_functions
    763 
    764     Sets the function pointers for the standard library functions.
    765 
    766     Return:
    767       0: on success
    768       -1: if the use global function pointers is not set.
    769 */
    770 int vpx_memory_tracker_set_functions(mem_track_malloc_func g_malloc_l
    771                                      , mem_track_calloc_func g_calloc_l
    772                                      , mem_track_realloc_func g_realloc_l
    773                                      , mem_track_free_func g_free_l
    774                                      , mem_track_memcpy_func g_memcpy_l
    775                                      , mem_track_memset_func g_memset_l
    776                                      , mem_track_memmove_func g_memmove_l)
    777 {
    778 #if USE_GLOBAL_FUNCTION_POINTERS
    779 
    780     if (g_malloc_l)
    781         g_malloc = g_malloc_l;
    782 
    783     if (g_calloc_l)
    784         g_calloc = g_calloc_l;
    785 
    786     if (g_realloc_l)
    787         g_realloc = g_realloc_l;
    788 
    789     if (g_free_l)
    790         g_free = g_free_l;
    791 
    792     if (g_memcpy_l)
    793         g_memcpy = g_memcpy_l;
    794 
    795     if (g_memset_l)
    796         g_memset = g_memset_l;
    797 
    798     if (g_memmove_l)
    799         g_memmove = g_memmove_l;
    800 
    801     return 0;
    802 #else
    803     (void)g_malloc_l;
    804     (void)g_calloc_l;
    805     (void)g_realloc_l;
    806     (void)g_free_l;
    807     (void)g_memcpy_l;
    808     (void)g_memset_l;
    809     (void)g_memmove_l;
    810     return -1;
    811 #endif
    812 }
    813