diff --git a/src/debug.c b/src/debug.c index 30213c9b9..a710f36b0 100644 --- a/src/debug.c +++ b/src/debug.c @@ -70,7 +70,6 @@ * non-null. It's only used by debuggers for core dump analysis. */ struct buffer *thread_dump_buffer = NULL; -unsigned int panic_started = 0; unsigned int debug_commands_issued = 0; /* dumps a backtrace of the current thread that is appended to buffer . @@ -397,10 +396,19 @@ static int debug_parse_cli_show_libs(char **args, char *payload, struct appctx * } #endif -/* dumps a state of all threads into the trash and on fd #2, then aborts. */ +/* Dumps a state of all threads into the trash and on fd #2, then aborts. + * A copy will be put into a trash chunk that's assigned to thread_dump_buffer + * so that the debugger can easily find it. This buffer might be truncated if + * too many threads are being dumped, but at least we'll dump them all on stderr. + * If thread_dump_buffer is set, it means that a panic has already begun. + */ void ha_panic() { - if (HA_ATOMIC_FETCH_ADD(&panic_started, 1) != 0) { + struct buffer *old; + unsigned int thr; + + old = NULL; + if (!HA_ATOMIC_CAS(&thread_dump_buffer, &old, get_trash_chunk())) { /* a panic dump is already in progress, let's not disturb it, * we'll be called via signal DEBUGSIG. By returning we may be * able to leave a current signal handler (e.g. WDT) so that @@ -408,11 +416,17 @@ void ha_panic() */ return; } - thread_dump_buffer = &trash; + chunk_reset(&trash); chunk_appendf(&trash, "Thread %u is about to kill the process.\n", tid + 1); - ha_thread_dump_all_to_trash(); - DISGUISE(write(2, trash.area, trash.data)); + + for (thr = 0; thr < global.nbthread; thr++) { + ha_thread_dump(&trash, thr); + DISGUISE(write(2, trash.area, trash.data)); + b_force_xfer(thread_dump_buffer, &trash, b_room(thread_dump_buffer)); + chunk_reset(&trash); + } + for (;;) abort(); }