From a5814f9de6009cc1763523109f50aae6bd1ff99e Mon Sep 17 00:00:00 2001 From: Andreas Gampe Date: Wed, 18 Jan 2017 21:43:16 -0800 Subject: [PATCH] ART: Add SigQuit Callback Add callback being triggered when the runtime handles SigQuit. Bug: 31684920 Test: m test-art-host-gtest-runtime_callbacks_test Change-Id: I23e3b256c654b6078c79b3897439d893ea79d96e --- runtime/runtime.cc | 6 +++++ runtime/runtime_callbacks.cc | 34 ++++++++++++++++++++++------- runtime/runtime_callbacks.h | 16 ++++++++++++++ runtime/runtime_callbacks_test.cc | 46 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 94 insertions(+), 8 deletions(-) diff --git a/runtime/runtime.cc b/runtime/runtime.cc index 5a5ed75b6..02466499c 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -1552,6 +1552,12 @@ void Runtime::DumpForSigQuit(std::ostream& os) { thread_list_->DumpForSigQuit(os); BaseMutex::DumpAll(os); + + // Inform anyone else who is interested in SigQuit. + { + ScopedObjectAccess soa(Thread::Current()); + callbacks_->SigQuit(); + } } void Runtime::DumpLockHolders(std::ostream& os) { diff --git a/runtime/runtime_callbacks.cc b/runtime/runtime_callbacks.cc index ee9eddab9..cd38ead2c 100644 --- a/runtime/runtime_callbacks.cc +++ b/runtime/runtime_callbacks.cc @@ -18,6 +18,7 @@ #include +#include "base/macros.h" #include "class_linker.h" #include "thread.h" @@ -27,13 +28,19 @@ void RuntimeCallbacks::AddThreadLifecycleCallback(ThreadLifecycleCallback* cb) { thread_callbacks_.push_back(cb); } -void RuntimeCallbacks::RemoveThreadLifecycleCallback(ThreadLifecycleCallback* cb) { - auto it = std::find(thread_callbacks_.begin(), thread_callbacks_.end(), cb); - if (it != thread_callbacks_.end()) { - thread_callbacks_.erase(it); +template +ALWAYS_INLINE +static inline void Remove(T* cb, std::vector* data) { + auto it = std::find(data->begin(), data->end(), cb); + if (it != data->end()) { + data->erase(it); } } +void RuntimeCallbacks::RemoveThreadLifecycleCallback(ThreadLifecycleCallback* cb) { + Remove(cb, &thread_callbacks_); +} + void RuntimeCallbacks::ThreadStart(Thread* self) { for (ThreadLifecycleCallback* cb : thread_callbacks_) { cb->ThreadStart(self); @@ -51,10 +58,7 @@ void RuntimeCallbacks::AddClassLoadCallback(ClassLoadCallback* cb) { } void RuntimeCallbacks::RemoveClassLoadCallback(ClassLoadCallback* cb) { - auto it = std::find(class_callbacks_.begin(), class_callbacks_.end(), cb); - if (it != class_callbacks_.end()) { - class_callbacks_.erase(it); - } + Remove(cb, &class_callbacks_); } void RuntimeCallbacks::ClassLoad(Handle klass) { @@ -69,4 +73,18 @@ void RuntimeCallbacks::ClassPrepare(Handle temp_klass, HandleSigQuit(); + } +} + } // namespace art diff --git a/runtime/runtime_callbacks.h b/runtime/runtime_callbacks.h index 5bdb44a44..d700cf2d5 100644 --- a/runtime/runtime_callbacks.h +++ b/runtime/runtime_callbacks.h @@ -48,6 +48,13 @@ class ThreadLifecycleCallback; // any state checking (is the listener enabled) in the listener itself. For an example, see // Dbg. +class RuntimeSigQuitCallback { + public: + virtual ~RuntimeSigQuitCallback() {} + + virtual void SigQuit() REQUIRES_SHARED(Locks::mutator_lock_) = 0; +}; + class RuntimeCallbacks { public: void AddThreadLifecycleCallback(ThreadLifecycleCallback* cb) REQUIRES(Locks::mutator_lock_); @@ -63,11 +70,20 @@ class RuntimeCallbacks { void ClassPrepare(Handle temp_klass, Handle klass) REQUIRES_SHARED(Locks::mutator_lock_); + void AddRuntimeSigQuitCallback(RuntimeSigQuitCallback* cb) + REQUIRES(Locks::mutator_lock_); + void RemoveRuntimeSigQuitCallback(RuntimeSigQuitCallback* cb) + REQUIRES(Locks::mutator_lock_); + + void SigQuit() REQUIRES_SHARED(Locks::mutator_lock_); + private: std::vector thread_callbacks_ GUARDED_BY(Locks::mutator_lock_); std::vector class_callbacks_ GUARDED_BY(Locks::mutator_lock_); + std::vector sigquit_callbacks_ + GUARDED_BY(Locks::mutator_lock_); }; } // namespace art diff --git a/runtime/runtime_callbacks_test.cc b/runtime/runtime_callbacks_test.cc index f05794dba..c96bfd4c7 100644 --- a/runtime/runtime_callbacks_test.cc +++ b/runtime/runtime_callbacks_test.cc @@ -17,6 +17,9 @@ #include "runtime_callbacks.h" #include "jni.h" +#include +#include +#include #include #include @@ -290,4 +293,47 @@ TEST_F(ClassLoadCallbackRuntimeCallbacksTest, ClassLoadCallback) { EXPECT_TRUE(expect2); } +class RuntimeSigQuitCallbackRuntimeCallbacksTest : public RuntimeCallbacksTest { + protected: + void AddListener() OVERRIDE REQUIRES(Locks::mutator_lock_) { + Runtime::Current()->GetRuntimeCallbacks()->AddRuntimeSigQuitCallback(&cb_); + } + void RemoveListener() OVERRIDE REQUIRES(Locks::mutator_lock_) { + Runtime::Current()->GetRuntimeCallbacks()->RemoveRuntimeSigQuitCallback(&cb_); + } + + struct Callback : public RuntimeSigQuitCallback { + void SigQuit() OVERRIDE { + ++sigquit_count; + } + + size_t sigquit_count = 0; + }; + + Callback cb_; +}; + +TEST_F(RuntimeSigQuitCallbackRuntimeCallbacksTest, SigQuit) { + // The runtime needs to be started for the signal handler. + Thread* self = Thread::Current(); + + self->TransitionFromSuspendedToRunnable(); + bool started = runtime_->Start(); + ASSERT_TRUE(started); + + EXPECT_EQ(0u, cb_.sigquit_count); + + kill(getpid(), SIGQUIT); + + // Try a few times. + for (size_t i = 0; i != 30; ++i) { + if (cb_.sigquit_count == 0) { + sleep(1); + } else { + break; + } + } + EXPECT_EQ(1u, cb_.sigquit_count); +} + } // namespace art -- 2.11.0