trace2 / tr2_tls.con commit trace2: fix tracing when NO_PTHREADS is defined (5fdae9d)
   1#include "cache.h"
   2#include "thread-utils.h"
   3#include "trace2/tr2_tls.h"
   4
   5/*
   6 * Initialize size of the thread stack for nested regions.
   7 * This is used to store nested region start times.  Note that
   8 * this stack is per-thread and not per-trace-key.
   9 */
  10#define TR2_REGION_NESTING_INITIAL_SIZE (100)
  11
  12static struct tr2tls_thread_ctx *tr2tls_thread_main;
  13static uint64_t tr2tls_us_start_main;
  14
  15static pthread_mutex_t tr2tls_mutex;
  16static pthread_key_t tr2tls_key;
  17
  18static int tr2_next_thread_id; /* modify under lock */
  19
  20struct tr2tls_thread_ctx *tr2tls_create_self(const char *thread_name)
  21{
  22        uint64_t us_now = getnanotime() / 1000;
  23        struct tr2tls_thread_ctx *ctx = xcalloc(1, sizeof(*ctx));
  24
  25        /*
  26         * Implicitly "tr2tls_push_self()" to capture the thread's start
  27         * time in array_us_start[0].  For the main thread this gives us the
  28         * application run time.
  29         */
  30        ctx->alloc = TR2_REGION_NESTING_INITIAL_SIZE;
  31        ctx->array_us_start = (uint64_t *)xcalloc(ctx->alloc, sizeof(uint64_t));
  32        ctx->array_us_start[ctx->nr_open_regions++] = us_now;
  33
  34        ctx->thread_id = tr2tls_locked_increment(&tr2_next_thread_id);
  35
  36        strbuf_init(&ctx->thread_name, 0);
  37        if (ctx->thread_id)
  38                strbuf_addf(&ctx->thread_name, "th%02d:", ctx->thread_id);
  39        strbuf_addstr(&ctx->thread_name, thread_name);
  40        if (ctx->thread_name.len > TR2_MAX_THREAD_NAME)
  41                strbuf_setlen(&ctx->thread_name, TR2_MAX_THREAD_NAME);
  42
  43        pthread_setspecific(tr2tls_key, ctx);
  44
  45        return ctx;
  46}
  47
  48struct tr2tls_thread_ctx *tr2tls_get_self(void)
  49{
  50        struct tr2tls_thread_ctx *ctx;
  51
  52        if (!HAVE_THREADS)
  53                return tr2tls_thread_main;
  54
  55        ctx = pthread_getspecific(tr2tls_key);
  56
  57        /*
  58         * If the thread-proc did not call trace2_thread_start(), we won't
  59         * have any TLS data associated with the current thread.  Fix it
  60         * here and silently continue.
  61         */
  62        if (!ctx)
  63                ctx = tr2tls_create_self("unknown");
  64
  65        return ctx;
  66}
  67
  68int tr2tls_is_main_thread(void)
  69{
  70        if (!HAVE_THREADS)
  71                return 1;
  72
  73        return pthread_getspecific(tr2tls_key) == tr2tls_thread_main;
  74}
  75
  76void tr2tls_unset_self(void)
  77{
  78        struct tr2tls_thread_ctx *ctx;
  79
  80        ctx = tr2tls_get_self();
  81
  82        pthread_setspecific(tr2tls_key, NULL);
  83
  84        free(ctx->array_us_start);
  85        free(ctx);
  86}
  87
  88void tr2tls_push_self(uint64_t us_now)
  89{
  90        struct tr2tls_thread_ctx *ctx = tr2tls_get_self();
  91
  92        ALLOC_GROW(ctx->array_us_start, ctx->nr_open_regions + 1, ctx->alloc);
  93        ctx->array_us_start[ctx->nr_open_regions++] = us_now;
  94}
  95
  96void tr2tls_pop_self(void)
  97{
  98        struct tr2tls_thread_ctx *ctx = tr2tls_get_self();
  99
 100        if (!ctx->nr_open_regions)
 101                BUG("no open regions in thread '%s'", ctx->thread_name.buf);
 102
 103        ctx->nr_open_regions--;
 104}
 105
 106void tr2tls_pop_unwind_self(void)
 107{
 108        struct tr2tls_thread_ctx *ctx = tr2tls_get_self();
 109
 110        while (ctx->nr_open_regions > 1)
 111                tr2tls_pop_self();
 112}
 113
 114uint64_t tr2tls_region_elasped_self(uint64_t us)
 115{
 116        struct tr2tls_thread_ctx *ctx;
 117        uint64_t us_start;
 118
 119        ctx = tr2tls_get_self();
 120        if (!ctx->nr_open_regions)
 121                return 0;
 122
 123        us_start = ctx->array_us_start[ctx->nr_open_regions - 1];
 124
 125        return us - us_start;
 126}
 127
 128uint64_t tr2tls_absolute_elapsed(uint64_t us)
 129{
 130        if (!tr2tls_thread_main)
 131                return 0;
 132
 133        return us - tr2tls_us_start_main;
 134}
 135
 136void tr2tls_init(void)
 137{
 138        pthread_key_create(&tr2tls_key, NULL);
 139        init_recursive_mutex(&tr2tls_mutex);
 140
 141        tr2tls_thread_main = tr2tls_create_self("main");
 142        /*
 143         * Keep a copy of the absolute start time of the main thread
 144         * in a fixed variable since other threads need to access it.
 145         * This also eliminates the need to lock accesses to the main
 146         * thread's array (because of reallocs).
 147         */
 148        tr2tls_us_start_main = tr2tls_thread_main->array_us_start[0];
 149}
 150
 151void tr2tls_release(void)
 152{
 153        tr2tls_unset_self();
 154        tr2tls_thread_main = NULL;
 155
 156        pthread_mutex_destroy(&tr2tls_mutex);
 157        pthread_key_delete(tr2tls_key);
 158}
 159
 160int tr2tls_locked_increment(int *p)
 161{
 162        int current_value;
 163
 164        pthread_mutex_lock(&tr2tls_mutex);
 165        current_value = *p;
 166        *p = current_value + 1;
 167        pthread_mutex_unlock(&tr2tls_mutex);
 168
 169        return current_value;
 170}