diff --git a/banned-die.h b/banned-die.h index cff1072397..52a93c67c6 100644 --- a/banned-die.h +++ b/banned-die.h @@ -17,6 +17,9 @@ #undef xstrdup #define xstrdup(str) BANNED(xstrdup) +#undef xcalloc +#define xcalloc(nmemb, size) BANNED(xcalloc) + #undef xstrfmt #define xstrfmt(...) BANNED(xstrfmt) diff --git a/trace2/tr2_ctr.c b/trace2/tr2_ctr.c index 20618a65b2..9920979030 100644 --- a/trace2/tr2_ctr.c +++ b/trace2/tr2_ctr.c @@ -55,7 +55,11 @@ static struct tr2_counter_metadata tr2_counter_metadata[TRACE2_NUMBER_OF_COUNTER void tr2_counter_increment(enum trace2_counter_id cid, uint64_t value) { struct tr2tls_thread_ctx *ctx = tr2tls_get_self(); - struct tr2_counter *c = &ctx->counter_block.counter[cid]; + struct tr2_counter *c; + + if (tr2tls_is_fallback(ctx)) + return; + c = &ctx->counter_block.counter[cid]; c->value += value; @@ -69,6 +73,8 @@ void tr2_update_final_counters(void) struct tr2tls_thread_ctx *ctx = tr2tls_get_self(); enum trace2_counter_id cid; + if (tr2tls_is_fallback(ctx)) + return; if (!ctx->used_any_counter) return; @@ -90,6 +96,8 @@ void tr2_emit_per_thread_counters(tr2_tgt_evt_counter_t *fn_apply) struct tr2tls_thread_ctx *ctx = tr2tls_get_self(); enum trace2_counter_id cid; + if (tr2tls_is_fallback(ctx)) + return; if (!ctx->used_any_per_thread_counter) return; diff --git a/trace2/tr2_tls.c b/trace2/tr2_tls.c index 5e4624d0b3..ace2cd438b 100644 --- a/trace2/tr2_tls.c +++ b/trace2/tr2_tls.c @@ -14,6 +14,9 @@ #define TR2_REGION_NESTING_INITIAL_SIZE (100) static struct tr2tls_thread_ctx *tr2tls_thread_main; +static struct tr2tls_thread_ctx tr2tls_thread_fallback = { + .thread_name = "unknown", +}; static uint64_t tr2tls_us_start_process; static pthread_mutex_t tr2tls_mutex; @@ -38,16 +41,23 @@ void tr2tls_start_process_clock(void) struct tr2tls_thread_ctx *tr2tls_create_self(const char *thread_base_name, uint64_t us_thread_start) { - struct tr2tls_thread_ctx *ctx = xcalloc(1, sizeof(*ctx)); + struct tr2tls_thread_ctx *ctx = calloc(1, sizeof(*ctx)); struct strbuf buf = STRBUF_INIT; + if (!ctx) + goto fallback; + /* * Implicitly "tr2tls_push_self()" to capture the thread's start * time in array_us_start[0]. For the main thread this gives us the * application run time. */ ctx->alloc = TR2_REGION_NESTING_INITIAL_SIZE; - ctx->array_us_start = (uint64_t *)xcalloc(ctx->alloc, sizeof(uint64_t)); + ctx->array_us_start = calloc(ctx->alloc, sizeof(uint64_t)); + if (!ctx->array_us_start) { + free(ctx); + goto fallback; + } ctx->array_us_start[ctx->nr_open_regions++] = us_thread_start; ctx->thread_id = tr2tls_locked_increment(&tr2_next_thread_id); @@ -63,6 +73,10 @@ struct tr2tls_thread_ctx *tr2tls_create_self(const char *thread_base_name, pthread_setspecific(tr2tls_key, ctx); return ctx; + +fallback: + pthread_setspecific(tr2tls_key, &tr2tls_thread_fallback); + return &tr2tls_thread_fallback; } struct tr2tls_thread_ctx *tr2tls_get_self(void) @@ -85,6 +99,11 @@ struct tr2tls_thread_ctx *tr2tls_get_self(void) return ctx; } +int tr2tls_is_fallback(const struct tr2tls_thread_ctx *ctx) +{ + return ctx == &tr2tls_thread_fallback; +} + int tr2tls_is_main_thread(void) { if (!HAVE_THREADS) @@ -101,6 +120,9 @@ void tr2tls_unset_self(void) pthread_setspecific(tr2tls_key, NULL); + if (tr2tls_is_fallback(ctx)) + return; + free((char *)ctx->thread_name); free(ctx->array_us_start); free(ctx); @@ -112,6 +134,9 @@ void tr2tls_push_self(uint64_t us_now) uint64_t *new_array; size_t new_alloc; + if (tr2tls_is_fallback(ctx)) + return; + if (ctx->nr_skipped_regions) { ctx->nr_skipped_regions++; return; @@ -143,6 +168,9 @@ void tr2tls_pop_self(void) { struct tr2tls_thread_ctx *ctx = tr2tls_get_self(); + if (tr2tls_is_fallback(ctx)) + return; + if (ctx->nr_skipped_regions) { ctx->nr_skipped_regions--; return; @@ -158,6 +186,9 @@ void tr2tls_pop_unwind_self(void) { struct tr2tls_thread_ctx *ctx = tr2tls_get_self(); + if (tr2tls_is_fallback(ctx)) + return; + while (ctx->nr_open_regions > 1) tr2tls_pop_self(); } @@ -168,6 +199,8 @@ uint64_t tr2tls_region_elasped_self(uint64_t us) uint64_t us_start; ctx = tr2tls_get_self(); + if (tr2tls_is_fallback(ctx)) + return 0; if (ctx->nr_skipped_regions) return 0; if (!ctx->nr_open_regions) @@ -189,6 +222,10 @@ uint64_t tr2tls_absolute_elapsed(uint64_t us) static void tr2tls_key_destructor(void *payload) { struct tr2tls_thread_ctx *ctx = payload; + + if (tr2tls_is_fallback(ctx)) + return; + free((char *)ctx->thread_name); free(ctx->array_us_start); free(ctx); diff --git a/trace2/tr2_tls.h b/trace2/tr2_tls.h index c365017923..4a0969c014 100644 --- a/trace2/tr2_tls.h +++ b/trace2/tr2_tls.h @@ -54,6 +54,12 @@ struct tr2tls_thread_ctx *tr2tls_create_self(const char *thread_base_name, */ struct tr2tls_thread_ctx *tr2tls_get_self(void); +/* + * Return true if the context is the non-allocating fallback used after an + * allocation failure. Callers must not modify a fallback context. + */ +int tr2tls_is_fallback(const struct tr2tls_thread_ctx *ctx); + /* * return true if the current thread is the main thread. */ diff --git a/trace2/tr2_tmr.c b/trace2/tr2_tmr.c index 275091c693..4dfc7afb4e 100644 --- a/trace2/tr2_tmr.c +++ b/trace2/tr2_tmr.c @@ -39,8 +39,11 @@ static struct tr2_timer_metadata tr2_timer_metadata[TRACE2_NUMBER_OF_TIMERS] = { void tr2_start_timer(enum trace2_timer_id tid) { struct tr2tls_thread_ctx *ctx = tr2tls_get_self(); - struct tr2_timer *t = &ctx->timer_block.timer[tid]; + struct tr2_timer *t; + if (tr2tls_is_fallback(ctx)) + return; + t = &ctx->timer_block.timer[tid]; t->recursion_count++; if (t->recursion_count > 1) return; /* ignore recursive starts */ @@ -51,10 +54,13 @@ void tr2_start_timer(enum trace2_timer_id tid) void tr2_stop_timer(enum trace2_timer_id tid) { struct tr2tls_thread_ctx *ctx = tr2tls_get_self(); - struct tr2_timer *t = &ctx->timer_block.timer[tid]; + struct tr2_timer *t; uint64_t ns_now; uint64_t ns_interval; + if (tr2tls_is_fallback(ctx)) + return; + t = &ctx->timer_block.timer[tid]; assert(t->recursion_count > 0); t->recursion_count--; @@ -92,6 +98,8 @@ void tr2_update_final_timers(void) struct tr2tls_thread_ctx *ctx = tr2tls_get_self(); enum trace2_timer_id tid; + if (tr2tls_is_fallback(ctx)) + return; if (!ctx->used_any_timer) return; @@ -138,6 +146,8 @@ void tr2_emit_per_thread_timers(tr2_tgt_evt_timer_t *fn_apply) struct tr2tls_thread_ctx *ctx = tr2tls_get_self(); enum trace2_timer_id tid; + if (tr2tls_is_fallback(ctx)) + return; if (!ctx->used_any_per_thread_timer) return;