Merge "Catch signals that happen inside a fault handler."
diff --git a/runtime/arch/arm/fault_handler_arm.cc b/runtime/arch/arm/fault_handler_arm.cc
index daa2dff..923ff4f 100644
--- a/runtime/arch/arm/fault_handler_arm.cc
+++ b/runtime/arch/arm/fault_handler_arm.cc
@@ -47,24 +47,6 @@
return instr_size;
}
-void FaultManager::HandleNestedSignal(int sig ATTRIBUTE_UNUSED, siginfo_t* info ATTRIBUTE_UNUSED,
- void* context) {
- // Note that in this handler we set up the registers and return to
- // longjmp directly rather than going through an assembly language stub. The
- // reason for this is that longjmp is (currently) in ARM mode and that would
- // require switching modes in the stub - incurring an unwanted relocation.
-
- struct ucontext *uc = reinterpret_cast<struct ucontext*>(context);
- struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
- Thread* self = Thread::Current();
- CHECK(self != nullptr); // This will cause a SIGABRT if self is null.
-
- sc->arm_r0 = reinterpret_cast<uintptr_t>(*self->GetNestedSignalState());
- sc->arm_r1 = 1;
- sc->arm_pc = reinterpret_cast<uintptr_t>(longjmp);
- VLOG(signals) << "longjmp address: " << reinterpret_cast<void*>(sc->arm_pc);
-}
-
void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo ATTRIBUTE_UNUSED, void* context,
ArtMethod** out_method,
uintptr_t* out_return_pc, uintptr_t* out_sp) {
diff --git a/runtime/arch/arm64/fault_handler_arm64.cc b/runtime/arch/arm64/fault_handler_arm64.cc
index c02be87..193af58 100644
--- a/runtime/arch/arm64/fault_handler_arm64.cc
+++ b/runtime/arch/arm64/fault_handler_arm64.cc
@@ -39,21 +39,6 @@
namespace art {
-void FaultManager::HandleNestedSignal(int sig ATTRIBUTE_UNUSED, siginfo_t* info ATTRIBUTE_UNUSED,
- void* context) {
- // To match the case used in ARM we return directly to the longjmp function
- // rather than through a trivial assembly language stub.
-
- struct ucontext *uc = reinterpret_cast<struct ucontext*>(context);
- struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
- Thread* self = Thread::Current();
- CHECK(self != nullptr); // This will cause a SIGABRT if self is null.
-
- sc->regs[0] = reinterpret_cast<uintptr_t>(*self->GetNestedSignalState());
- sc->regs[1] = 1;
- sc->pc = reinterpret_cast<uintptr_t>(longjmp);
-}
-
void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo ATTRIBUTE_UNUSED, void* context,
ArtMethod** out_method,
uintptr_t* out_return_pc, uintptr_t* out_sp) {
diff --git a/runtime/arch/mips/fault_handler_mips.cc b/runtime/arch/mips/fault_handler_mips.cc
index 1792f31..f9c19e8 100644
--- a/runtime/arch/mips/fault_handler_mips.cc
+++ b/runtime/arch/mips/fault_handler_mips.cc
@@ -35,10 +35,6 @@
namespace art {
-void FaultManager::HandleNestedSignal(int sig ATTRIBUTE_UNUSED, siginfo_t* info ATTRIBUTE_UNUSED,
- void* context ATTRIBUTE_UNUSED) {
-}
-
void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo, void* context,
ArtMethod** out_method,
uintptr_t* out_return_pc, uintptr_t* out_sp) {
diff --git a/runtime/arch/mips64/fault_handler_mips64.cc b/runtime/arch/mips64/fault_handler_mips64.cc
index 709cab5..d668d3a 100644
--- a/runtime/arch/mips64/fault_handler_mips64.cc
+++ b/runtime/arch/mips64/fault_handler_mips64.cc
@@ -35,10 +35,6 @@
namespace art {
-void FaultManager::HandleNestedSignal(int sig ATTRIBUTE_UNUSED, siginfo_t* info ATTRIBUTE_UNUSED,
- void* context ATTRIBUTE_UNUSED) {
-}
-
void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo, void* context,
ArtMethod** out_method,
uintptr_t* out_return_pc, uintptr_t* out_sp) {
diff --git a/runtime/arch/x86/fault_handler_x86.cc b/runtime/arch/x86/fault_handler_x86.cc
index a4d6bb4..f407ebf 100644
--- a/runtime/arch/x86/fault_handler_x86.cc
+++ b/runtime/arch/x86/fault_handler_x86.cc
@@ -75,12 +75,6 @@
extern "C" void art_quick_throw_stack_overflow();
extern "C" void art_quick_test_suspend();
-// Note this is different from the others (no underscore on 64 bit mac) due to
-// the way the symbol is defined in the .S file.
-// TODO: fix the symbols for 64 bit mac - there is a double underscore prefix for some
-// of them.
-extern "C" void art_nested_signal_return();
-
// Get the size of an instruction in bytes.
// Return 0 if the instruction is not handled.
static uint32_t GetInstructionSize(const uint8_t* pc) {
@@ -247,21 +241,6 @@
return pc - startpc;
}
-void FaultManager::HandleNestedSignal(int, siginfo_t*, void* context) {
- // For the Intel architectures we need to go to an assembly language
- // stub. This is because the 32 bit call to longjmp is much different
- // from the 64 bit ABI call and pushing things onto the stack inside this
- // handler was unwieldy and ugly. The use of the stub means we can keep
- // this code the same for both 32 and 64 bit.
-
- Thread* self = Thread::Current();
- CHECK(self != nullptr); // This will cause a SIGABRT if self is null.
-
- struct ucontext* uc = reinterpret_cast<struct ucontext*>(context);
- uc->CTX_JMP_BUF = reinterpret_cast<uintptr_t>(*self->GetNestedSignalState());
- uc->CTX_EIP = reinterpret_cast<uintptr_t>(art_nested_signal_return);
-}
-
void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo, void* context,
ArtMethod** out_method,
uintptr_t* out_return_pc, uintptr_t* out_sp) {
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index ff7ba92..5f38dc8 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -2137,19 +2137,6 @@
ret
END_FUNCTION art_quick_string_compareto
-// Return from a nested signal:
-// Entry:
-// eax: address of jmp_buf in TLS
-
-DEFINE_FUNCTION art_nested_signal_return
- SETUP_GOT_NOSAVE ebx // sets %ebx for call into PLT
- movl LITERAL(1), %ecx
- PUSH ecx // second arg to longjmp (1)
- PUSH eax // first arg to longjmp (jmp_buf)
- call PLT_SYMBOL(longjmp)
- UNREACHABLE
-END_FUNCTION art_nested_signal_return
-
// Create a function `name` calling the ReadBarrier::Mark routine,
// getting its argument and returning its result through register
// `reg`, saving and restoring all caller-save registers.
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index 8a663d1..e87b165 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -2100,18 +2100,6 @@
ret
END_FUNCTION art_quick_instance_of
-
-// Return from a nested signal:
-// Entry:
-// rdi: address of jmp_buf in TLS
-
-DEFINE_FUNCTION art_nested_signal_return
- // first arg to longjmp is already in correct register
- movq LITERAL(1), %rsi // second arg to longjmp (1)
- call PLT_SYMBOL(longjmp)
- UNREACHABLE
-END_FUNCTION art_nested_signal_return
-
// Create a function `name` calling the ReadBarrier::Mark routine,
// getting its argument and returning its result through register
// `reg`, saving and restoring all caller-save registers.
diff --git a/runtime/entrypoints/quick/quick_throw_entrypoints.cc b/runtime/entrypoints/quick/quick_throw_entrypoints.cc
index c8ee99a..1520e13 100644
--- a/runtime/entrypoints/quick/quick_throw_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_throw_entrypoints.cc
@@ -62,9 +62,7 @@
extern "C" NO_RETURN void artThrowNullPointerExceptionFromSignal(uintptr_t addr, Thread* self)
REQUIRES_SHARED(Locks::mutator_lock_) {
ScopedQuickEntrypointChecks sqec(self);
- self->NoteSignalBeingHandled();
ThrowNullPointerExceptionFromDexPC(/* check_address */ true, addr);
- self->NoteSignalHandlerDone();
self->QuickDeliverException();
}
@@ -95,9 +93,7 @@
extern "C" NO_RETURN void artThrowStackOverflowFromCode(Thread* self)
REQUIRES_SHARED(Locks::mutator_lock_) {
ScopedQuickEntrypointChecks sqec(self);
- self->NoteSignalBeingHandled();
ThrowStackOverflowError(self);
- self->NoteSignalHandlerDone();
self->QuickDeliverException();
}
diff --git a/runtime/entrypoints_order_test.cc b/runtime/entrypoints_order_test.cc
index d0687ce..55a4625 100644
--- a/runtime/entrypoints_order_test.cc
+++ b/runtime/entrypoints_order_test.cc
@@ -133,9 +133,8 @@
EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_alloc_stack_top, thread_local_alloc_stack_end,
sizeof(void*));
EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_alloc_stack_end, held_mutexes, sizeof(void*));
- EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, held_mutexes, nested_signal_state,
+ EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, held_mutexes, flip_function,
sizeof(void*) * kLockLevelCount);
- EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, nested_signal_state, flip_function, sizeof(void*));
EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, flip_function, method_verifier, sizeof(void*));
EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, method_verifier, thread_local_mark_stack, sizeof(void*));
EXPECT_OFFSET_DIFF(Thread, tlsPtr_.thread_local_mark_stack, Thread, wait_mutex_, sizeof(void*),
diff --git a/runtime/fault_handler.cc b/runtime/fault_handler.cc
index f9345b6..64128cc 100644
--- a/runtime/fault_handler.cc
+++ b/runtime/fault_handler.cc
@@ -28,47 +28,6 @@
#include "thread-inl.h"
#include "verify_object-inl.h"
-// Note on nested signal support
-// -----------------------------
-//
-// Typically a signal handler should not need to deal with signals that occur within it.
-// However, when a SIGSEGV occurs that is in generated code and is not one of the
-// handled signals (implicit checks), we call a function to try to dump the stack
-// to the log. This enhances the debugging experience but may have the side effect
-// that it may not work. If the cause of the original SIGSEGV is a corrupted stack or other
-// memory region, the stack backtrace code may run into trouble and may either crash
-// or fail with an abort (SIGABRT). In either case we don't want that (new) signal to
-// mask the original signal and thus prevent useful debug output from being presented.
-//
-// In order to handle this situation, before we call the stack tracer we do the following:
-//
-// 1. shutdown the fault manager so that we are talking to the real signal management
-// functions rather than those in sigchain.
-// 2. use pthread_sigmask to allow SIGSEGV and SIGABRT signals to be delivered to the
-// thread running the signal handler.
-// 3. set the handler for SIGSEGV and SIGABRT to a secondary signal handler.
-// 4. save the thread's state to the TLS of the current thread using 'setjmp'
-//
-// We then call the stack tracer and one of two things may happen:
-// a. it completes successfully
-// b. it crashes and a signal is raised.
-//
-// In the former case, we fall through and everything is fine. In the latter case
-// our secondary signal handler gets called in a signal context. This results in
-// a call to FaultManager::HandledNestedSignal(), an archirecture specific function
-// whose purpose is to call 'longjmp' on the jmp_buf saved in the TLS of the current
-// thread. This results in a return with a non-zero value from 'setjmp'. We detect this
-// and write something to the log to tell the user that it happened.
-//
-// Regardless of how we got there, we reach the code after the stack tracer and we
-// restore the signal states to their original values, reinstate the fault manager (thus
-// reestablishing the signal chain) and continue.
-
-// This is difficult to test with a runtime test. To invoke the nested signal code
-// on any signal, uncomment the following line and run something that throws a
-// NullPointerException.
-// #define TEST_NESTED_SIGNAL
-
namespace art {
// Static fault manger object accessed by signal handler.
FaultManager fault_manager;
@@ -83,11 +42,6 @@
fault_manager.HandleFault(sig, info, context);
}
-// Signal handler for dealing with a nested signal.
-static void art_nested_signal_handler(int sig, siginfo_t* info, void* context) {
- fault_manager.HandleNestedSignal(sig, info, context);
-}
-
FaultManager::FaultManager() : initialized_(false) {
sigaction(SIGSEGV, nullptr, &oldaction_);
}
@@ -156,122 +110,93 @@
DCHECK(self != nullptr);
DCHECK(Runtime::Current() != nullptr);
DCHECK(Runtime::Current()->IsStarted());
-
- // Now set up the nested signal handler.
-
- // TODO: add SIGSEGV back to the nested signals when we can handle running out stack gracefully.
- static const int handled_nested_signals[] = {SIGABRT};
- constexpr size_t num_handled_nested_signals = arraysize(handled_nested_signals);
-
- // Release the fault manager so that it will remove the signal chain for
- // SIGSEGV and we call the real sigaction.
- fault_manager.Release();
-
- // The action for SIGSEGV should be the default handler now.
-
- // Unblock the signals we allow so that they can be delivered in the signal handler.
- sigset_t sigset;
- sigemptyset(&sigset);
- for (int signal : handled_nested_signals) {
- sigaddset(&sigset, signal);
- }
- pthread_sigmask(SIG_UNBLOCK, &sigset, nullptr);
-
- // If we get a signal in this code we want to invoke our nested signal
- // handler.
- struct sigaction action;
- struct sigaction oldactions[num_handled_nested_signals];
- action.sa_sigaction = art_nested_signal_handler;
-
- // Explicitly mask out SIGSEGV and SIGABRT from the nested signal handler. This
- // should be the default but we definitely don't want these happening in our
- // nested signal handler.
- sigemptyset(&action.sa_mask);
- for (int signal : handled_nested_signals) {
- sigaddset(&action.sa_mask, signal);
- }
-
- action.sa_flags = SA_SIGINFO | SA_ONSTACK;
-#if !defined(__APPLE__) && !defined(__mips__)
- action.sa_restorer = nullptr;
-#endif
-
- // Catch handled signals to invoke our nested handler.
- bool success = true;
- for (size_t i = 0; i < num_handled_nested_signals; ++i) {
- success = sigaction(handled_nested_signals[i], &action, &oldactions[i]) == 0;
- if (!success) {
- PLOG(ERROR) << "Unable to set up nested signal handler";
- break;
+ for (const auto& handler : other_handlers_) {
+ if (handler->Action(sig, info, context)) {
+ return true;
}
}
-
- if (success) {
- // Save the current state and call the handlers. If anything causes a signal
- // our nested signal handler will be invoked and this will longjmp to the saved
- // state.
- if (setjmp(*self->GetNestedSignalState()) == 0) {
- for (const auto& handler : other_handlers_) {
- if (handler->Action(sig, info, context)) {
- // Restore the signal handlers, reinit the fault manager and return. Signal was
- // handled.
- for (size_t i = 0; i < num_handled_nested_signals; ++i) {
- success = sigaction(handled_nested_signals[i], &oldactions[i], nullptr) == 0;
- if (!success) {
- PLOG(ERROR) << "Unable to restore signal handler";
- }
- }
- fault_manager.Init();
- return true;
- }
- }
- } else {
- LOG(ERROR) << "Nested signal detected - original signal being reported";
- }
-
- // Restore the signal handlers.
- for (size_t i = 0; i < num_handled_nested_signals; ++i) {
- success = sigaction(handled_nested_signals[i], &oldactions[i], nullptr) == 0;
- if (!success) {
- PLOG(ERROR) << "Unable to restore signal handler";
- }
- }
- }
-
- // Now put the fault manager back in place.
- fault_manager.Init();
return false;
}
+class ScopedSignalUnblocker {
+ public:
+ explicit ScopedSignalUnblocker(const std::initializer_list<int>& signals) {
+ sigset_t new_mask;
+ sigemptyset(&new_mask);
+ for (int signal : signals) {
+ sigaddset(&new_mask, signal);
+ }
+ if (sigprocmask(SIG_UNBLOCK, &new_mask, &previous_mask_) != 0) {
+ PLOG(FATAL) << "failed to unblock signals";
+ }
+ }
+
+ ~ScopedSignalUnblocker() {
+ if (sigprocmask(SIG_SETMASK, &previous_mask_, nullptr) != 0) {
+ PLOG(FATAL) << "failed to unblock signals";
+ }
+ }
+
+ private:
+ sigset_t previous_mask_;
+};
+
+class ScopedHandlingSignalSetter {
+ public:
+ explicit ScopedHandlingSignalSetter(Thread* thread) : thread_(thread) {
+ CHECK(!thread->HandlingSignal());
+ thread_->SetHandlingSignal(true);
+ }
+
+ ~ScopedHandlingSignalSetter() {
+ CHECK(thread_->HandlingSignal());
+ thread_->SetHandlingSignal(false);
+ }
+
+ private:
+ Thread* thread_;
+};
+
void FaultManager::HandleFault(int sig, siginfo_t* info, void* context) {
// BE CAREFUL ALLOCATING HERE INCLUDING USING LOG(...)
//
// If malloc calls abort, it will be holding its lock.
// If the handler tries to call malloc, it will deadlock.
- VLOG(signals) << "Handling fault";
- if (IsInGeneratedCode(info, context, true)) {
- VLOG(signals) << "in generated code, looking for handler";
- for (const auto& handler : generated_code_handlers_) {
- VLOG(signals) << "invoking Action on handler " << handler;
- if (handler->Action(sig, info, context)) {
-#ifdef TEST_NESTED_SIGNAL
- // In test mode we want to fall through to stack trace handler
- // on every signal (in reality this will cause a crash on the first
- // signal).
- break;
-#else
- // We have handled a signal so it's time to return from the
- // signal handler to the appropriate place.
- return;
-#endif
- }
- }
- // We hit a signal we didn't handle. This might be something for which
- // we can give more information about so call all registered handlers to see
- // if it is.
- if (HandleFaultByOtherHandlers(sig, info, context)) {
+ // Use a thread local field to track whether we're recursing, and fall back.
+ // (e.g.. if one of our handlers crashed)
+ Thread* thread = Thread::Current();
+
+ if (thread != nullptr && !thread->HandlingSignal()) {
+ // Unblock some signals and set thread->handling_signal_ to true,
+ // so that we can catch crashes in our signal handler.
+ ScopedHandlingSignalSetter setter(thread);
+ ScopedSignalUnblocker unblocker { SIGABRT, SIGBUS, SIGSEGV }; // NOLINT
+
+ VLOG(signals) << "Handling fault";
+
+#ifdef TEST_NESTED_SIGNAL
+ // Simulate a crash in a handler.
+ raise(SIGSEGV);
+#endif
+
+ if (IsInGeneratedCode(info, context, true)) {
+ VLOG(signals) << "in generated code, looking for handler";
+ for (const auto& handler : generated_code_handlers_) {
+ VLOG(signals) << "invoking Action on handler " << handler;
+ if (handler->Action(sig, info, context)) {
+ // We have handled a signal so it's time to return from the
+ // signal handler to the appropriate place.
+ return;
+ }
+ }
+
+ // We hit a signal we didn't handle. This might be something for which
+ // we can give more information about so call all registered handlers to
+ // see if it is.
+ if (HandleFaultByOtherHandlers(sig, info, context)) {
return;
+ }
}
}
@@ -417,11 +342,7 @@
bool JavaStackTraceHandler::Action(int sig ATTRIBUTE_UNUSED, siginfo_t* siginfo, void* context) {
// Make sure that we are in the generated code, but we may not have a dex pc.
-#ifdef TEST_NESTED_SIGNAL
- bool in_generated_code = true;
-#else
bool in_generated_code = manager_->IsInGeneratedCode(siginfo, context, false);
-#endif
if (in_generated_code) {
LOG(ERROR) << "Dumping java stack trace for crash in generated code";
ArtMethod* method = nullptr;
@@ -432,12 +353,6 @@
manager_->GetMethodAndReturnPcAndSp(siginfo, context, &method, &return_pc, &sp);
// Inside of generated code, sp[0] is the method, so sp is the frame.
self->SetTopOfStack(reinterpret_cast<ArtMethod**>(sp));
-#ifdef TEST_NESTED_SIGNAL
- // To test the nested signal handler we raise a signal here. This will cause the
- // nested signal handler to be called and perform a longjmp back to the setjmp
- // above.
- abort();
-#endif
self->DumpJavaStack(LOG_STREAM(ERROR));
}
diff --git a/runtime/fault_handler.h b/runtime/fault_handler.h
index 56e0fb7..ce59ba7 100644
--- a/runtime/fault_handler.h
+++ b/runtime/fault_handler.h
@@ -45,7 +45,6 @@
void EnsureArtActionInFrontOfSignalChain();
void HandleFault(int sig, siginfo_t* info, void* context);
- void HandleNestedSignal(int sig, siginfo_t* info, void* context);
// Added handlers are owned by the fault handler and will be freed on Shutdown().
void AddHandler(FaultHandler* handler, bool generated_code);
diff --git a/runtime/thread.cc b/runtime/thread.cc
index ff66cc1..30a4046 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -1934,7 +1934,6 @@
wait_cond_ = new ConditionVariable("a thread wait condition variable", *wait_mutex_);
tlsPtr_.instrumentation_stack = new std::deque<instrumentation::InstrumentationStackFrame>;
tlsPtr_.name = new std::string(kThreadNameDuringStartup);
- tlsPtr_.nested_signal_state = static_cast<jmp_buf*>(malloc(sizeof(jmp_buf)));
static_assert((sizeof(Thread) % 4) == 0U,
"art::Thread has a size which is not a multiple of 4.");
@@ -2118,7 +2117,6 @@
delete tlsPtr_.instrumentation_stack;
delete tlsPtr_.name;
delete tlsPtr_.deps_or_stack_trace_sample.stack_trace_sample;
- free(tlsPtr_.nested_signal_state);
Runtime::Current()->GetHeap()->AssertThreadLocalBuffersAreRevoked(this);
diff --git a/runtime/thread.h b/runtime/thread.h
index d5fd9e9..de0b892 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -1115,21 +1115,12 @@
return tlsPtr_.mterp_alt_ibase;
}
- // Notify that a signal is being handled. This is to protect us from doing recursive
- // NPE handling after a SIGSEGV.
- void NoteSignalBeingHandled() {
- if (tls32_.handling_signal_) {
- LOG(FATAL) << "Detected signal while processing a signal";
- }
- tls32_.handling_signal_ = true;
+ bool HandlingSignal() const {
+ return tls32_.handling_signal_;
}
- void NoteSignalHandlerDone() {
- tls32_.handling_signal_ = false;
- }
-
- jmp_buf* GetNestedSignalState() {
- return tlsPtr_.nested_signal_state;
+ void SetHandlingSignal(bool handling_signal) {
+ tls32_.handling_signal_ = handling_signal;
}
bool IsTransitioningToRunnable() const {
@@ -1460,7 +1451,7 @@
thread_local_start(nullptr), thread_local_pos(nullptr), thread_local_end(nullptr),
thread_local_objects(0), mterp_current_ibase(nullptr), mterp_default_ibase(nullptr),
mterp_alt_ibase(nullptr), thread_local_alloc_stack_top(nullptr),
- thread_local_alloc_stack_end(nullptr), nested_signal_state(nullptr),
+ thread_local_alloc_stack_end(nullptr),
flip_function(nullptr), method_verifier(nullptr), thread_local_mark_stack(nullptr) {
std::fill(held_mutexes, held_mutexes + kLockLevelCount, nullptr);
}
@@ -1606,9 +1597,6 @@
// Support for Mutex lock hierarchy bug detection.
BaseMutex* held_mutexes[kLockLevelCount];
- // Recorded thread state for nested signals.
- jmp_buf* nested_signal_state;
-
// The function used for thread flip.
Closure* flip_function;