diff options
author | 2018-11-28 08:27:27 -0800 | |
---|---|---|
committer | 2018-12-06 11:37:19 -0800 | |
commit | 44f67607b33e36c118fe0f62c062865b2bc8bd8f (patch) | |
tree | a17f7b4a6f7affe866377ac5ee7924195ef8fbe5 | |
parent | 7fbc4a59ba2e60d869313d7961662430df83b2cb (diff) |
ART: Rewrite Runtime fault message to be lock-free
To avoid the lock in a general header, rewrite the fault message
(that is almost unused) to be lock-free. Store the string as a
heap object owned by Runtime.
Bug: 119869270
Test: mmma art
Test: m test-art-host
Change-Id: Ib1e027a1543c46d25953119f05792f0e874d6a3d
-rw-r--r-- | runtime/runtime-inl.h | 1 | ||||
-rw-r--r-- | runtime/runtime.cc | 26 | ||||
-rw-r--r-- | runtime/runtime.h | 24 | ||||
-rw-r--r-- | runtime/runtime_common.cc | 9 |
4 files changed, 44 insertions, 16 deletions
diff --git a/runtime/runtime-inl.h b/runtime/runtime-inl.h index e6cc471ae6..2ffaf98103 100644 --- a/runtime/runtime-inl.h +++ b/runtime/runtime-inl.h @@ -23,6 +23,7 @@ #include "art_method.h" #include "base/callee_save_type.h" #include "base/casts.h" +#include "base/mutex.h" #include "entrypoints/quick/callee_save_frame.h" #include "gc_root-inl.h" #include "interpreter/mterp/mterp.h" diff --git a/runtime/runtime.cc b/runtime/runtime.cc index 84526f3332..d53cc07b71 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -234,8 +234,7 @@ Runtime::Runtime() class_linker_(nullptr), signal_catcher_(nullptr), java_vm_(nullptr), - fault_message_lock_("Fault message lock"), - fault_message_(""), + fault_message_(nullptr), threads_being_born_(0), shutdown_cond_(new ConditionVariable("Runtime shutdown", *Locks::runtime_shutdown_lock_)), shutting_down_(false), @@ -2367,8 +2366,27 @@ void Runtime::RecordResolveString(ObjPtr<mirror::DexCache> dex_cache, } void Runtime::SetFaultMessage(const std::string& message) { - MutexLock mu(Thread::Current(), fault_message_lock_); - fault_message_ = message; + std::string* new_msg = new std::string(message); + std::string* cur_msg = fault_message_.exchange(new_msg); + delete cur_msg; +} + +std::string Runtime::GetFaultMessage() { + // Retrieve the message. Temporarily replace with null so that SetFaultMessage will not delete + // the string in parallel. + std::string* cur_msg = fault_message_.exchange(nullptr); + + // Make a copy of the string. + std::string ret = cur_msg == nullptr ? "" : *cur_msg; + + // Put the message back if it hasn't been updated. + std::string* null_str = nullptr; + if (!fault_message_.compare_exchange_strong(null_str, cur_msg)) { + // Already replaced. + delete cur_msg; + } + + return ret; } void Runtime::AddCurrentRuntimeFeaturesAsDex2OatArguments(std::vector<std::string>* argv) diff --git a/runtime/runtime.h b/runtime/runtime.h index c74647e465..5450c0f057 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -28,9 +28,9 @@ #include <vector> #include "arch/instruction_set.h" +#include "base/locks.h" #include "base/macros.h" #include "base/mem_map.h" -#include "base/mutex.h" #include "deoptimization_kind.h" #include "dex/dex_file_types.h" #include "experimental_flags.h" @@ -511,12 +511,7 @@ class Runtime { void RecordResolveString(ObjPtr<mirror::DexCache> dex_cache, dex::StringIndex string_idx) const REQUIRES_SHARED(Locks::mutator_lock_); - void SetFaultMessage(const std::string& message) REQUIRES(!fault_message_lock_); - // Only read by the signal handler, NO_THREAD_SAFETY_ANALYSIS to prevent lock order violations - // with the unexpected_signal_lock_. - const std::string& GetFaultMessage() NO_THREAD_SAFETY_ANALYSIS { - return fault_message_; - } + void SetFaultMessage(const std::string& message); void AddCurrentRuntimeFeaturesAsDex2OatArguments(std::vector<std::string>* arg_vector) const; @@ -824,6 +819,12 @@ class Runtime { void VisitConstantRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_); + // Note: To be lock-free, GetFaultMessage temporarily replaces the lock message with null. + // As such, there is a window where a call will return an empty string. In general, + // only aborting code should retrieve this data (via GetFaultMessageForAbortLogging + // friend). + std::string GetFaultMessage(); + // A pointer to the active runtime or null. static Runtime* instance_; @@ -909,9 +910,9 @@ class Runtime { std::unique_ptr<jit::JitCodeCache> jit_code_cache_; std::unique_ptr<jit::JitOptions> jit_options_; - // Fault message, printed when we get a SIGSEGV. - Mutex fault_message_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; - std::string fault_message_ GUARDED_BY(fault_message_lock_); + // Fault message, printed when we get a SIGSEGV. Stored as a native-heap object and accessed + // lock-free, so needs to be atomic. + std::atomic<std::string*> fault_message_; // A non-zero value indicates that a thread has been created but not yet initialized. Guarded by // the shutdown lock so that threads aren't born while we're shutting down. @@ -1111,6 +1112,9 @@ class Runtime { uint32_t verifier_logging_threshold_ms_; + // Note: See comments on GetFaultMessage. + friend std::string GetFaultMessageForAbortLogging(); + DISALLOW_COPY_AND_ASSIGN(Runtime); }; diff --git a/runtime/runtime_common.cc b/runtime/runtime_common.cc index eae2505ce9..5676577696 100644 --- a/runtime/runtime_common.cc +++ b/runtime/runtime_common.cc @@ -371,6 +371,11 @@ static bool IsTimeoutSignal(int signal_number) { #pragma GCC diagnostic ignored "-Wframe-larger-than=" #endif +std::string GetFaultMessageForAbortLogging() { + Runtime* runtime = Runtime::Current(); + return (runtime != nullptr) ? runtime->GetFaultMessage() : ""; +} + static void HandleUnexpectedSignalCommonDump(int signal_number, siginfo_t* info, void* raw_context, @@ -427,9 +432,9 @@ static void HandleUnexpectedSignalCommonDump(int signal_number, } if (dump_on_stderr) { - std::cerr << "Fault message: " << runtime->GetFaultMessage() << std::endl; + std::cerr << "Fault message: " << GetFaultMessageForAbortLogging() << std::endl; } else { - LOG(FATAL_WITHOUT_ABORT) << "Fault message: " << runtime->GetFaultMessage(); + LOG(FATAL_WITHOUT_ABORT) << "Fault message: " << GetFaultMessageForAbortLogging(); } } } |