Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /**************************************************************************
  2.  *
  3.  * Copyright 2010 Luca Barbieri
  4.  *
  5.  * Permission is hereby granted, free of charge, to any person obtaining
  6.  * a copy of this software and associated documentation files (the
  7.  * "Software"), to deal in the Software without restriction, including
  8.  * without limitation the rights to use, copy, modify, merge, publish,
  9.  * distribute, sublicense, and/or sell copies of the Software, and to
  10.  * permit persons to whom the Software is furnished to do so, subject to
  11.  * the following conditions:
  12.  *
  13.  * The above copyright notice and this permission notice (including the
  14.  * next paragraph) shall be included in all copies or substantial
  15.  * portions of the Software.
  16.  *
  17.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  18.  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  19.  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  20.  * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
  21.  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  22.  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  23.  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  24.  *
  25.  **************************************************************************/
  26.  
  27. #if defined(DEBUG)
  28.  
  29. /* see http://www.mozilla.org/performance/refcnt-balancer.html for what do with the output
  30.  * on Linux, use tools/addr2line.sh to postprocess it before anything else
  31.  **/
  32.  
  33. #include <stdio.h>
  34.  
  35. #include "util/u_debug.h"
  36. #include "util/u_debug_refcnt.h"
  37. #include "util/u_debug_stack.h"
  38. #include "util/u_debug_symbol.h"
  39. #include "util/u_string.h"
  40. #include "util/u_hash_table.h"
  41. #include "os/os_thread.h"
  42.  
  43. int debug_refcnt_state;
  44.  
  45. FILE* stream;
  46.  
  47. /* TODO: maybe move this serial machinery to a stand-alone module and expose it? */
  48. pipe_static_mutex(serials_mutex);
  49.  
  50. static struct util_hash_table* serials_hash;
  51. static unsigned serials_last;
  52.  
  53. static unsigned hash_ptr(void* p)
  54. {
  55.    return (unsigned)(uintptr_t)p;
  56. }
  57.  
  58. static int compare_ptr(void* a, void* b)
  59. {
  60.    if(a == b)
  61.       return 0;
  62.    else if(a < b)
  63.       return -1;
  64.    else
  65.       return 1;
  66. }
  67.  
  68. static boolean debug_serial(void* p, unsigned* pserial)
  69. {
  70.    unsigned serial;
  71.    boolean found = TRUE;
  72. #ifdef PIPE_SUBSYSTEM_WINDOWS_USER
  73.    static boolean first = TRUE;
  74.  
  75.    if (first) {
  76.       pipe_mutex_init(serials_mutex);
  77.       first = FALSE;
  78.    }
  79. #endif
  80.  
  81.    pipe_mutex_lock(serials_mutex);
  82.    if(!serials_hash)
  83.       serials_hash = util_hash_table_create(hash_ptr, compare_ptr);
  84.    serial = (unsigned)(uintptr_t)util_hash_table_get(serials_hash, p);
  85.    if(!serial)
  86.    {
  87.       /* time to stop logging... (you'll have a 100 GB logfile at least at this point)
  88.        * TODO: avoid this
  89.        */
  90.       serial = ++serials_last;
  91.       if(!serial)
  92.       {
  93.          debug_error("More than 2^32 objects detected, aborting.\n");
  94.          os_abort();
  95.       }
  96.  
  97.       util_hash_table_set(serials_hash, p, (void*)(uintptr_t)serial);
  98.       found = FALSE;
  99.    }
  100.    pipe_mutex_unlock(serials_mutex);
  101.    *pserial = serial;
  102.    return found;
  103. }
  104.  
  105. static void debug_serial_delete(void* p)
  106. {
  107.    pipe_mutex_lock(serials_mutex);
  108.    util_hash_table_remove(serials_hash, p);
  109.    pipe_mutex_unlock(serials_mutex);
  110. }
  111.  
  112. #define STACK_LEN 64
  113.  
  114. static void dump_stack(const char* symbols[STACK_LEN])
  115. {
  116.    unsigned i;
  117.    for(i = 0; i < STACK_LEN; ++i)
  118.    {
  119.       if(symbols[i])
  120.          fprintf(stream, "%s\n", symbols[i]);
  121.    }
  122.    fprintf(stream, "\n");
  123. }
  124.  
  125. void debug_reference_slowpath(const struct pipe_reference* p, debug_reference_descriptor get_desc, int change)
  126. {
  127.    if(debug_refcnt_state < 0)
  128.       return;
  129.  
  130.    if(!debug_refcnt_state)
  131.    {
  132.       const char* filename = debug_get_option("GALLIUM_REFCNT_LOG", NULL);
  133.       if(filename && filename[0])
  134.          stream = fopen(filename, "wt");
  135.  
  136.       if(stream)
  137.          debug_refcnt_state = 1;
  138.       else
  139.          debug_refcnt_state = -1;
  140.    }
  141.  
  142.    if(debug_refcnt_state > 0)
  143.    {
  144.       struct debug_stack_frame frames[STACK_LEN];
  145.       const char* symbols[STACK_LEN];
  146.       char buf[1024];
  147.  
  148.       unsigned i;
  149.       unsigned refcnt = p->count;
  150.       unsigned serial;
  151.       boolean existing = debug_serial((void*)p, &serial);
  152.  
  153.       debug_backtrace_capture(frames, 1, STACK_LEN);
  154.       for(i = 0; i < STACK_LEN; ++i)
  155.       {
  156.          if(frames[i].function)
  157.             symbols[i] = debug_symbol_name_cached(frames[i].function);
  158.          else
  159.             symbols[i] = 0;
  160.       }
  161.  
  162.       get_desc(buf, p);
  163.  
  164.       if(!existing)
  165.       {
  166.          fprintf(stream, "<%s> %p %u Create\n", buf, (void *) p, serial);
  167.          dump_stack(symbols);
  168.  
  169.          /* this is there to provide a gradual change even if we don't see the initialization */
  170.          for(i = 1; i <= refcnt - change; ++i)
  171.          {
  172.             fprintf(stream, "<%s> %p %u AddRef %u\n", buf, (void *) p,
  173.                     serial, i);
  174.             dump_stack(symbols);
  175.          }
  176.       }
  177.  
  178.       if(change)
  179.       {
  180.          fprintf(stream, "<%s> %p %u %s %u\n", buf, (void *) p, serial,
  181.                  change > 0 ? "AddRef" : "Release", refcnt);
  182.          dump_stack(symbols);
  183.       }
  184.  
  185.       if(!refcnt)
  186.       {
  187.          debug_serial_delete((void*)p);
  188.          fprintf(stream, "<%s> %p %u Destroy\n", buf, (void *) p, serial);
  189.          dump_stack(symbols);
  190.       }
  191.  
  192.       fflush(stream);
  193.    }
  194. }
  195. #endif
  196.