* 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 <buf>.
}
#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
*/
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();
}