Git fork
at reftables-rust 203 lines 4.5 kB view raw
1#include "git-compat-util.h" 2#include "strbuf.h" 3#include "thread-utils.h" 4#include "trace.h" 5#include "trace2/tr2_tls.h" 6 7/* 8 * Initialize size of the thread stack for nested regions. 9 * This is used to store nested region start times. Note that 10 * this stack is per-thread and not per-trace-key. 11 */ 12#define TR2_REGION_NESTING_INITIAL_SIZE (100) 13 14static struct tr2tls_thread_ctx *tr2tls_thread_main; 15static uint64_t tr2tls_us_start_process; 16 17static pthread_mutex_t tr2tls_mutex; 18static pthread_key_t tr2tls_key; 19 20static int tr2_next_thread_id; /* modify under lock */ 21 22void tr2tls_start_process_clock(void) 23{ 24 if (tr2tls_us_start_process) 25 return; 26 27 /* 28 * Keep the absolute start time of the process (i.e. the main 29 * process) in a fixed variable since other threads need to 30 * access it. This allows them to do that without a lock on 31 * main thread's array data (because of reallocs). 32 */ 33 tr2tls_us_start_process = getnanotime() / 1000; 34} 35 36struct tr2tls_thread_ctx *tr2tls_create_self(const char *thread_base_name, 37 uint64_t us_thread_start) 38{ 39 struct tr2tls_thread_ctx *ctx = xcalloc(1, sizeof(*ctx)); 40 struct strbuf buf = STRBUF_INIT; 41 42 /* 43 * Implicitly "tr2tls_push_self()" to capture the thread's start 44 * time in array_us_start[0]. For the main thread this gives us the 45 * application run time. 46 */ 47 ctx->alloc = TR2_REGION_NESTING_INITIAL_SIZE; 48 ctx->array_us_start = (uint64_t *)xcalloc(ctx->alloc, sizeof(uint64_t)); 49 ctx->array_us_start[ctx->nr_open_regions++] = us_thread_start; 50 51 ctx->thread_id = tr2tls_locked_increment(&tr2_next_thread_id); 52 53 strbuf_init(&buf, 0); 54 if (ctx->thread_id) 55 strbuf_addf(&buf, "th%02d:", ctx->thread_id); 56 strbuf_addstr(&buf, thread_base_name); 57 if (buf.len > TR2_MAX_THREAD_NAME) 58 strbuf_setlen(&buf, TR2_MAX_THREAD_NAME); 59 ctx->thread_name = strbuf_detach(&buf, NULL); 60 61 pthread_setspecific(tr2tls_key, ctx); 62 63 return ctx; 64} 65 66struct tr2tls_thread_ctx *tr2tls_get_self(void) 67{ 68 struct tr2tls_thread_ctx *ctx; 69 70 if (!HAVE_THREADS) 71 return tr2tls_thread_main; 72 73 ctx = pthread_getspecific(tr2tls_key); 74 75 /* 76 * If the current thread's thread-proc did not call 77 * trace2_thread_start(), then the thread will not have any 78 * thread-local storage. Create it now and silently continue. 79 */ 80 if (!ctx) 81 ctx = tr2tls_create_self("unknown", getnanotime() / 1000); 82 83 return ctx; 84} 85 86int tr2tls_is_main_thread(void) 87{ 88 if (!HAVE_THREADS) 89 return 1; 90 91 return pthread_getspecific(tr2tls_key) == tr2tls_thread_main; 92} 93 94void tr2tls_unset_self(void) 95{ 96 struct tr2tls_thread_ctx *ctx; 97 98 ctx = tr2tls_get_self(); 99 100 pthread_setspecific(tr2tls_key, NULL); 101 102 free((char *)ctx->thread_name); 103 free(ctx->array_us_start); 104 free(ctx); 105} 106 107void tr2tls_push_self(uint64_t us_now) 108{ 109 struct tr2tls_thread_ctx *ctx = tr2tls_get_self(); 110 111 ALLOC_GROW(ctx->array_us_start, ctx->nr_open_regions + 1, ctx->alloc); 112 ctx->array_us_start[ctx->nr_open_regions++] = us_now; 113} 114 115void tr2tls_pop_self(void) 116{ 117 struct tr2tls_thread_ctx *ctx = tr2tls_get_self(); 118 119 if (!ctx->nr_open_regions) 120 BUG("no open regions in thread '%s'", ctx->thread_name); 121 122 ctx->nr_open_regions--; 123} 124 125void tr2tls_pop_unwind_self(void) 126{ 127 struct tr2tls_thread_ctx *ctx = tr2tls_get_self(); 128 129 while (ctx->nr_open_regions > 1) 130 tr2tls_pop_self(); 131} 132 133uint64_t tr2tls_region_elasped_self(uint64_t us) 134{ 135 struct tr2tls_thread_ctx *ctx; 136 uint64_t us_start; 137 138 ctx = tr2tls_get_self(); 139 if (!ctx->nr_open_regions) 140 return 0; 141 142 us_start = ctx->array_us_start[ctx->nr_open_regions - 1]; 143 144 return us - us_start; 145} 146 147uint64_t tr2tls_absolute_elapsed(uint64_t us) 148{ 149 if (!tr2tls_thread_main) 150 return 0; 151 152 return us - tr2tls_us_start_process; 153} 154 155static void tr2tls_key_destructor(void *payload) 156{ 157 struct tr2tls_thread_ctx *ctx = payload; 158 free((char *)ctx->thread_name); 159 free(ctx->array_us_start); 160 free(ctx); 161} 162 163void tr2tls_init(void) 164{ 165 tr2tls_start_process_clock(); 166 167 pthread_key_create(&tr2tls_key, tr2tls_key_destructor); 168 init_recursive_mutex(&tr2tls_mutex); 169 170 tr2tls_thread_main = 171 tr2tls_create_self("main", tr2tls_us_start_process); 172} 173 174void tr2tls_release(void) 175{ 176 tr2tls_unset_self(); 177 tr2tls_thread_main = NULL; 178 179 pthread_mutex_destroy(&tr2tls_mutex); 180 pthread_key_delete(tr2tls_key); 181} 182 183int tr2tls_locked_increment(int *p) 184{ 185 int current_value; 186 187 pthread_mutex_lock(&tr2tls_mutex); 188 current_value = *p; 189 *p = current_value + 1; 190 pthread_mutex_unlock(&tr2tls_mutex); 191 192 return current_value; 193} 194 195void tr2tls_lock(void) 196{ 197 pthread_mutex_lock(&tr2tls_mutex); 198} 199 200void tr2tls_unlock(void) 201{ 202 pthread_mutex_unlock(&tr2tls_mutex); 203}