ART: Experiment with timeout dumping
In an attempt to diagnose some timeout dumping issues, allow a recursive
unexpected signal. Also print the new signal number irrespectively.
Test: m test-art-host
Test: manual: send timeout signal to run-test
Test: manual: send timeout signal to run-test, then send sigbus to run-test
Change-Id: Idf198b264a7e5868bdf444f323921c946584c650
diff --git a/runtime/runtime_common.cc b/runtime/runtime_common.cc
index 41bfb58..010c6e7 100644
--- a/runtime/runtime_common.cc
+++ b/runtime/runtime_common.cc
@@ -370,30 +370,11 @@
#pragma GCC diagnostic ignored "-Wframe-larger-than="
#endif
-void HandleUnexpectedSignalCommon(int signal_number,
- siginfo_t* info,
- void* raw_context,
- bool handle_timeout_signal,
- bool dump_on_stderr) {
- static bool handling_unexpected_signal = false;
- if (handling_unexpected_signal) {
- LogHelper::LogLineLowStack(__FILE__,
- __LINE__,
- ::android::base::FATAL_WITHOUT_ABORT,
- "HandleUnexpectedSignal reentered\n");
- if (handle_timeout_signal) {
- if (IsTimeoutSignal(signal_number)) {
- // Ignore a recursive timeout.
- return;
- }
- }
- _exit(1);
- }
- handling_unexpected_signal = true;
-
- gAborting++; // set before taking any locks
- MutexLock mu(Thread::Current(), *Locks::unexpected_signal_lock_);
-
+static void HandleUnexpectedSignalCommonDump(int signal_number,
+ siginfo_t* info,
+ void* raw_context,
+ bool handle_timeout_signal,
+ bool dump_on_stderr) {
auto logger = [&](auto& stream) {
bool has_address = (signal_number == SIGILL || signal_number == SIGBUS ||
signal_number == SIGFPE || signal_number == SIGSEGV);
@@ -452,6 +433,71 @@
}
}
+void HandleUnexpectedSignalCommon(int signal_number,
+ siginfo_t* info,
+ void* raw_context,
+ bool handle_timeout_signal,
+ bool dump_on_stderr) {
+ // Local _static_ storing the currently handled signal (or -1).
+ static int handling_unexpected_signal = -1;
+
+ // Whether the dump code should be run under the unexpected-signal lock. For diagnostics we
+ // allow recursive unexpected-signals in certain cases - avoid a deadlock.
+ bool grab_lock = true;
+
+ if (handling_unexpected_signal != -1) {
+ LogHelper::LogLineLowStack(__FILE__,
+ __LINE__,
+ ::android::base::FATAL_WITHOUT_ABORT,
+ "HandleUnexpectedSignal reentered\n");
+ // Print the signal number. Don't use any standard functions, just some arithmetic. Just best
+ // effort, with a minimal buffer.
+ if (0 < signal_number && signal_number < 100) {
+ char buf[] = { ' ',
+ 'S',
+ static_cast<char>('0' + (signal_number / 10)),
+ static_cast<char>('0' + (signal_number % 10)),
+ '\n',
+ 0 };
+ LogHelper::LogLineLowStack(__FILE__,
+ __LINE__,
+ ::android::base::FATAL_WITHOUT_ABORT,
+ buf);
+ }
+ if (handle_timeout_signal) {
+ if (IsTimeoutSignal(signal_number)) {
+ // Ignore a recursive timeout.
+ return;
+ }
+ }
+ // If we were handling a timeout signal, try to go on. Otherwise hard-exit.
+ // This relies on the expectation that we'll only ever get one timeout signal.
+ if (!handle_timeout_signal || handling_unexpected_signal != GetTimeoutSignal()) {
+ _exit(1);
+ }
+ grab_lock = false; // The "outer" handling instance already holds the lock.
+ }
+ handling_unexpected_signal = signal_number;
+
+ gAborting++; // set before taking any locks
+
+ if (grab_lock) {
+ MutexLock mu(Thread::Current(), *Locks::unexpected_signal_lock_);
+
+ HandleUnexpectedSignalCommonDump(signal_number,
+ info,
+ raw_context,
+ handle_timeout_signal,
+ dump_on_stderr);
+ } else {
+ HandleUnexpectedSignalCommonDump(signal_number,
+ info,
+ raw_context,
+ handle_timeout_signal,
+ dump_on_stderr);
+ }
+}
+
#if defined(__APPLE__)
#pragma GCC diagnostic pop
#endif