diff options
Diffstat (limited to 'runtime/thread.cc')
-rw-r--r-- | runtime/thread.cc | 112 |
1 files changed, 59 insertions, 53 deletions
diff --git a/runtime/thread.cc b/runtime/thread.cc index dcbe1382e0..dca08959f4 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -622,7 +622,7 @@ void* Thread::CreateCallback(void* arg) { // while threads are being born). CHECK(!runtime->IsShuttingDownLocked()); // Note: given that the JNIEnv is created in the parent thread, the only failure point here is - // a mess in InitStackHwm. We do not have a reasonable way to recover from that, so abort + // a mess in InitStack. We do not have a reasonable way to recover from that, so abort // the runtime in such a case. In case this ever changes, we need to make sure here to // delete the tmp_jni_env, as we own it at this point. CHECK(self->Init(runtime->GetThreadList(), runtime->GetJavaVM(), self->tlsPtr_.tmp_jni_env)); @@ -729,9 +729,8 @@ static size_t FixStackSize(size_t stack_size) { return stack_size; } -// Return the nearest page-aligned address below the current stack top. -NO_INLINE -static uint8_t* FindStackTop() { +template <> +NO_INLINE uint8_t* Thread::FindStackTop<StackType::kHardware>() { return reinterpret_cast<uint8_t*>( AlignDown(__builtin_frame_address(0), gPageSize)); } @@ -739,16 +738,17 @@ static uint8_t* FindStackTop() { // Install a protected region in the stack. This is used to trigger a SIGSEGV if a stack // overflow is detected. It is located right below the stack_begin_. ATTRIBUTE_NO_SANITIZE_ADDRESS +template <StackType stack_type> void Thread::InstallImplicitProtection() { - uint8_t* pregion = tlsPtr_.stack_begin - GetStackOverflowProtectedSize(); + uint8_t* pregion = GetStackBegin<stack_type>() - GetStackOverflowProtectedSize(); // Page containing current top of stack. - uint8_t* stack_top = FindStackTop(); + uint8_t* stack_top = FindStackTop<stack_type>(); // Try to directly protect the stack. VLOG(threads) << "installing stack protected region at " << std::hex << static_cast<void*>(pregion) << " to " << static_cast<void*>(pregion + GetStackOverflowProtectedSize() - 1); - if (ProtectStack(/* fatal_on_error= */ false)) { + if (ProtectStack<stack_type>(/* fatal_on_error= */ false)) { // Tell the kernel that we won't be needing these pages any more. // NB. madvise will probably write zeroes into the memory (on linux it does). size_t unwanted_size = @@ -778,7 +778,7 @@ void Thread::InstallImplicitProtection() { // (Defensively) first remove the protection on the protected region as we'll want to read // and write it. Ignore errors. - UnprotectStack(); + UnprotectStack<stack_type>(); VLOG(threads) << "Need to map in stack for thread at " << std::hex << static_cast<void*>(pregion); @@ -821,7 +821,7 @@ void Thread::InstallImplicitProtection() { static_cast<void*>(pregion + GetStackOverflowProtectedSize() - 1); // Protect the bottom of the stack to prevent read/write to it. - ProtectStack(/* fatal_on_error= */ true); + ProtectStack<stack_type>(/* fatal_on_error= */ true); // Tell the kernel that we won't be needing these pages any more. // NB. madvise will probably write zeroes into the memory (on linux it does). @@ -948,6 +948,11 @@ void Thread::CreateNativeThread(JNIEnv* env, jobject java_peer, size_t stack_siz } } +static void GetThreadStack(pthread_t thread, + void** stack_base, + size_t* stack_size, + size_t* guard_size); + bool Thread::Init(ThreadList* thread_list, JavaVMExt* java_vm, JNIEnvExt* jni_env_ext) { // This function does all the initialization that must be run by the native thread it applies to. // (When we create a new thread from managed code, we allocate the Thread* in Thread::Create so @@ -963,7 +968,14 @@ bool Thread::Init(ThreadList* thread_list, JavaVMExt* java_vm, JNIEnvExt* jni_en ScopedTrace trace("Thread::Init"); SetUpAlternateSignalStack(); - if (!InitStackHwm()) { + + void* read_stack_base = nullptr; + size_t read_stack_size = 0; + size_t read_guard_size = 0; + GetThreadStack(tlsPtr_.pthread_self, &read_stack_base, &read_stack_size, &read_guard_size); + if (!InitStack<kNativeStackType>(reinterpret_cast<uint8_t*>(read_stack_base), + read_stack_size, + read_guard_size)) { return false; } InitCpu(); @@ -1331,15 +1343,12 @@ static void GetThreadStack(pthread_t thread, #endif } -bool Thread::InitStackHwm() { - ScopedTrace trace("InitStackHwm"); - void* read_stack_base; - size_t read_stack_size; - size_t read_guard_size; - GetThreadStack(tlsPtr_.pthread_self, &read_stack_base, &read_stack_size, &read_guard_size); +template <StackType stack_type> +bool Thread::InitStack(uint8_t* read_stack_base, size_t read_stack_size, size_t read_guard_size) { + ScopedTrace trace("InitStack"); - tlsPtr_.stack_begin = reinterpret_cast<uint8_t*>(read_stack_base); - tlsPtr_.stack_size = read_stack_size; + SetStackBegin<stack_type>(read_stack_base); + SetStackSize<stack_type>(read_stack_size); // The minimum stack size we can cope with is the protected region size + stack overflow check // region size + some memory for normal stack usage. @@ -1372,8 +1381,16 @@ bool Thread::InitStackHwm() { return false; } + std::string stack_type_str = ""; + if constexpr (stack_type == kNativeStackType) { + stack_type_str = "Native"; + } else if constexpr (stack_type == kQuickStackType) { + stack_type_str = "Quick"; + } + // This is included in the SIGQUIT output, but it's useful here for thread debugging. - VLOG(threads) << StringPrintf("Native stack is at %p (%s with %s guard)", + VLOG(threads) << StringPrintf("%s stack is at %p (%s with %s guard)", + stack_type_str.c_str(), read_stack_base, PrettySize(read_stack_size).c_str(), PrettySize(read_guard_size).c_str()); @@ -1384,7 +1401,7 @@ bool Thread::InitStackHwm() { bool implicit_stack_check = runtime->GetImplicitStackOverflowChecks() && !runtime->IsAotCompiler(); - ResetDefaultStackEnd(); + ResetDefaultStackEnd<stack_type>(); // Install the protected region if we are doing implicit overflow checks. if (implicit_stack_check) { @@ -1392,15 +1409,18 @@ bool Thread::InitStackHwm() { // to install our own region so we need to move the limits // of the stack to make room for it. - tlsPtr_.stack_begin += read_guard_size + GetStackOverflowProtectedSize(); - tlsPtr_.stack_end += read_guard_size + GetStackOverflowProtectedSize(); - tlsPtr_.stack_size -= read_guard_size + GetStackOverflowProtectedSize(); + SetStackBegin<stack_type>(GetStackBegin<stack_type>() + read_guard_size + + GetStackOverflowProtectedSize()); + SetStackEnd<stack_type>(GetStackEnd<stack_type>() + read_guard_size + + GetStackOverflowProtectedSize()); + SetStackSize<stack_type>(GetStackSize<stack_type>() - (read_guard_size + + GetStackOverflowProtectedSize())); - InstallImplicitProtection(); + InstallImplicitProtection<stack_type>(); } // Consistency check. - CHECK_GT(FindStackTop(), reinterpret_cast<void*>(tlsPtr_.stack_end)); + CHECK_GT(FindStackTop<stack_type>(), reinterpret_cast<void*>(GetStackEnd<stack_type>())); return true; } @@ -2115,9 +2135,10 @@ void Thread::DumpState(std::ostream& os, const Thread* thread, pid_t tid) { << " core=" << task_cpu << " HZ=" << sysconf(_SC_CLK_TCK) << "\n"; if (thread != nullptr) { - os << " | stack=" << reinterpret_cast<void*>(thread->tlsPtr_.stack_begin) << "-" - << reinterpret_cast<void*>(thread->tlsPtr_.stack_end) << " stackSize=" - << PrettySize(thread->tlsPtr_.stack_size) << "\n"; + // TODO(Simulator): Also dump the simulated stack if one exists. + os << " | stack=" << reinterpret_cast<void*>(thread->GetStackBegin<kNativeStackType>()) + << "-" << reinterpret_cast<void*>(thread->GetStackEnd<kNativeStackType>()) + << " stackSize=" << PrettySize(thread->GetStackSize<kNativeStackType>()) << "\n"; // Dump the held mutexes. os << " | held mutexes="; for (size_t i = 0; i < kLockLevelCount; ++i) { @@ -2804,12 +2825,17 @@ class JniTransitionReferenceVisitor : public StackVisitor { bool found_; }; +bool Thread::IsRawObjOnQuickStack(uint8_t* raw_obj) const { + return (static_cast<size_t>(raw_obj - GetStackBegin<kQuickStackType>()) < + GetStackSize<kQuickStackType>()); +} + bool Thread::IsJniTransitionReference(jobject obj) const { DCHECK(obj != nullptr); // We need a non-const pointer for stack walk even if we're not modifying the thread state. Thread* thread = const_cast<Thread*>(this); uint8_t* raw_obj = reinterpret_cast<uint8_t*>(obj); - if (static_cast<size_t>(raw_obj - tlsPtr_.stack_begin) < tlsPtr_.stack_size) { + if (IsRawObjOnQuickStack(raw_obj)) { JniTransitionReferenceVisitor</*kPointsToStack=*/ true> visitor(thread, raw_obj); visitor.WalkStack(); return visitor.Found(); @@ -4622,28 +4648,6 @@ void Thread::VerifyStackImpl() { } } -// Set the stack end to that to be used during a stack overflow -void Thread::SetStackEndForStackOverflow() { - // During stack overflow we allow use of the full stack. - if (tlsPtr_.stack_end == tlsPtr_.stack_begin) { - // However, we seem to have already extended to use the full stack. - LOG(ERROR) << "Need to increase kStackOverflowReservedBytes (currently " - << GetStackOverflowReservedBytes(kRuntimeISA) << ")?"; - DumpStack(LOG_STREAM(ERROR)); - LOG(FATAL) << "Recursive stack overflow."; - } - - tlsPtr_.stack_end = tlsPtr_.stack_begin; - - // Remove the stack overflow protection if is it set up. - bool implicit_stack_check = Runtime::Current()->GetImplicitStackOverflowChecks(); - if (implicit_stack_check) { - if (!UnprotectStack()) { - LOG(ERROR) << "Unable to remove stack protection for stack overflow"; - } - } -} - void Thread::SetTlab(uint8_t* start, uint8_t* end, uint8_t* limit) { DCHECK_LE(start, end); DCHECK_LE(end, limit); @@ -4691,8 +4695,9 @@ std::ostream& operator<<(std::ostream& os, const Thread& thread) { return os; } +template <StackType stack_type> bool Thread::ProtectStack(bool fatal_on_error) { - void* pregion = tlsPtr_.stack_begin - GetStackOverflowProtectedSize(); + void* pregion = GetStackBegin<stack_type>() - GetStackOverflowProtectedSize(); VLOG(threads) << "Protecting stack at " << pregion; if (mprotect(pregion, GetStackOverflowProtectedSize(), PROT_NONE) == -1) { if (fatal_on_error) { @@ -4707,8 +4712,9 @@ bool Thread::ProtectStack(bool fatal_on_error) { return true; } +template <StackType stack_type> bool Thread::UnprotectStack() { - void* pregion = tlsPtr_.stack_begin - GetStackOverflowProtectedSize(); + void* pregion = GetStackBegin<stack_type>() - GetStackOverflowProtectedSize(); VLOG(threads) << "Unprotecting stack at " << pregion; return mprotect(pregion, GetStackOverflowProtectedSize(), PROT_READ|PROT_WRITE) == 0; } |