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