diff options
| -rw-r--r-- | runtime/debugger.cc | 3 | ||||
| -rw-r--r-- | runtime/instrumentation.cc | 7 | ||||
| -rw-r--r-- | runtime/native/java_lang_Thread.cc | 1 | ||||
| -rw-r--r-- | runtime/runtime.cc | 8 | ||||
| -rw-r--r-- | runtime/thread_list.cc | 9 | ||||
| -rw-r--r-- | runtime/thread_state.h | 1 | ||||
| -rw-r--r-- | runtime/trace.h | 13 | ||||
| -rw-r--r-- | test/304-method-tracing/expected.txt | 0 | ||||
| -rw-r--r-- | test/304-method-tracing/info.txt | 1 | ||||
| -rwxr-xr-x | test/304-method-tracing/run | 18 | ||||
| -rw-r--r-- | test/304-method-tracing/src/Main.java | 48 |
11 files changed, 97 insertions, 12 deletions
diff --git a/runtime/debugger.cc b/runtime/debugger.cc index 6161aff647..c95be0154a 100644 --- a/runtime/debugger.cc +++ b/runtime/debugger.cc @@ -1996,13 +1996,14 @@ JDWP::JdwpThreadStatus Dbg::ToJdwpThreadStatus(ThreadState state) { case kTerminated: return JDWP::TS_ZOMBIE; case kTimedWaiting: + case kWaitingForCheckPointsToRun: case kWaitingForDebuggerSend: case kWaitingForDebuggerSuspension: case kWaitingForDebuggerToAttach: case kWaitingForDeoptimization: case kWaitingForGcToComplete: - case kWaitingForCheckPointsToRun: case kWaitingForJniOnLoad: + case kWaitingForMethodTracingStart: case kWaitingForSignalCatcherOutput: case kWaitingInMainDebuggerLoop: case kWaitingInMainSignalCatcherLoop: diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc index 8f5da83f8f..f459b590eb 100644 --- a/runtime/instrumentation.cc +++ b/runtime/instrumentation.cc @@ -137,7 +137,8 @@ void Instrumentation::InstallStubsForMethod(mirror::ArtMethod* method) { new_quick_code = GetQuickResolutionTrampoline(class_linker); } } else { // !uninstall - if ((interpreter_stubs_installed_ || IsDeoptimized(method)) && !method->IsNative()) { + if ((interpreter_stubs_installed_ || forced_interpret_only_ || IsDeoptimized(method)) && + !method->IsNative()) { new_portable_code = GetPortableToInterpreterBridge(); new_quick_code = GetQuickToInterpreterBridge(); } else { @@ -150,7 +151,9 @@ void Instrumentation::InstallStubsForMethod(mirror::ArtMethod* method) { new_quick_code = class_linker->GetQuickOatCodeFor(method); DCHECK(new_quick_code != GetQuickToInterpreterBridgeTrampoline(class_linker)); if (entry_exit_stubs_installed_ && new_quick_code != GetQuickToInterpreterBridge()) { - DCHECK(new_portable_code != GetPortableToInterpreterBridge()); + // TODO: portable to quick bridge. Bug: 8196384. We cannot enable the check below as long + // as GetPortableToQuickBridge() == GetPortableToInterpreterBridge(). + // DCHECK(new_portable_code != GetPortableToInterpreterBridge()); new_portable_code = GetPortableToInterpreterBridge(); new_quick_code = GetQuickInstrumentationEntryPoint(); } diff --git a/runtime/native/java_lang_Thread.cc b/runtime/native/java_lang_Thread.cc index 86db893cf8..bae67f20e8 100644 --- a/runtime/native/java_lang_Thread.cc +++ b/runtime/native/java_lang_Thread.cc @@ -85,6 +85,7 @@ static jint Thread_nativeGetStatus(JNIEnv* env, jobject java_thread, jboolean ha case kWaitingForJniOnLoad: return kJavaWaiting; case kWaitingForSignalCatcherOutput: return kJavaWaiting; case kWaitingInMainSignalCatcherLoop: return kJavaWaiting; + case kWaitingForMethodTracingStart: return kJavaWaiting; case kSuspended: return kJavaRunnable; // Don't add a 'default' here so the compiler can spot incompatible enum changes. } diff --git a/runtime/runtime.cc b/runtime/runtime.cc index 3b14aaa767..efa205e079 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -147,6 +147,13 @@ Runtime::Runtime() } Runtime::~Runtime() { + if (method_trace_ && Thread::Current() == nullptr) { + // We need a current thread to shutdown method tracing: re-attach it now. + JNIEnv* unused_env; + if (GetJavaVM()->AttachCurrentThread(&unused_env, nullptr) != JNI_OK) { + LOG(ERROR) << "Could not attach current thread before runtime shutdown."; + } + } if (dump_gc_performance_on_shutdown_) { // This can't be called from the Heap destructor below because it // could call RosAlloc::InspectAll() which needs the thread_list @@ -681,6 +688,7 @@ bool Runtime::Init(const Options& raw_options, bool ignore_unrecognized) { Trace::SetDefaultClockSource(options->profile_clock_source_); if (options->method_trace_) { + ScopedThreadStateChange tsc(self, kWaitingForMethodTracingStart); Trace::Start(options->method_trace_file_.c_str(), -1, options->method_trace_file_size_, 0, false, false, 0); } diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc index d20a45942d..54732fae04 100644 --- a/runtime/thread_list.cc +++ b/runtime/thread_list.cc @@ -153,8 +153,8 @@ void ThreadList::AssertThreadsAreSuspended(Thread* self, Thread* ignore1, Thread #if HAVE_TIMED_RWLOCK // Attempt to rectify locks so that we dump thread list with required locks before exiting. -static void UnsafeLogFatalForThreadSuspendAllTimeout(Thread* self) NO_THREAD_SAFETY_ANALYSIS __attribute__((noreturn)); -static void UnsafeLogFatalForThreadSuspendAllTimeout(Thread* self) { +static void UnsafeLogFatalForThreadSuspendAllTimeout() NO_THREAD_SAFETY_ANALYSIS __attribute__((noreturn)); +static void UnsafeLogFatalForThreadSuspendAllTimeout() { Runtime* runtime = Runtime::Current(); std::ostringstream ss; ss << "Thread suspend timeout\n"; @@ -332,7 +332,7 @@ void ThreadList::SuspendAll() { #if HAVE_TIMED_RWLOCK // Timeout if we wait more than 30 seconds. if (!Locks::mutator_lock_->ExclusiveLockWithTimeout(self, 30 * 1000, 0)) { - UnsafeLogFatalForThreadSuspendAllTimeout(self); + UnsafeLogFatalForThreadSuspendAllTimeout(); } #else Locks::mutator_lock_->ExclusiveLock(self); @@ -351,6 +351,7 @@ void ThreadList::SuspendAll() { void ThreadList::ResumeAll() { Thread* self = Thread::Current(); + DCHECK(self != nullptr); VLOG(threads) << *self << " ResumeAll starting"; @@ -587,7 +588,7 @@ void ThreadList::SuspendAllForDebugger() { #if HAVE_TIMED_RWLOCK // Timeout if we wait more than 30 seconds. if (!Locks::mutator_lock_->ExclusiveLockWithTimeout(self, 30 * 1000, 0)) { - UnsafeLogFatalForThreadSuspendAllTimeout(self); + UnsafeLogFatalForThreadSuspendAllTimeout(); } else { Locks::mutator_lock_->ExclusiveUnlock(self); } diff --git a/runtime/thread_state.h b/runtime/thread_state.h index 57bf4f1438..0e47d2166b 100644 --- a/runtime/thread_state.h +++ b/runtime/thread_state.h @@ -38,6 +38,7 @@ enum ThreadState { kWaitingForSignalCatcherOutput, // WAITING TS_WAIT waiting for signal catcher IO to complete kWaitingInMainSignalCatcherLoop, // WAITING TS_WAIT blocking/reading/processing signals kWaitingForDeoptimization, // WAITING TS_WAIT waiting for deoptimization suspend all + kWaitingForMethodTracingStart, // WAITING TS_WAIT waiting for method tracing to start kStarting, // NEW TS_WAIT native thread started, not yet ready to run managed code kNative, // RUNNABLE TS_RUNNING running in a JNI native method kSuspended, // RUNNABLE TS_RUNNING suspended by GC or debugger diff --git a/runtime/trace.h b/runtime/trace.h index 08da16f789..3f5d80a4bf 100644 --- a/runtime/trace.h +++ b/runtime/trace.h @@ -65,11 +65,14 @@ class Trace FINAL : public instrumentation::InstrumentationListener { static void Start(const char* trace_filename, int trace_fd, int buffer_size, int flags, bool direct_to_ddms, bool sampling_enabled, int interval_us) - LOCKS_EXCLUDED(Locks::mutator_lock_, - Locks::thread_list_lock_, - Locks::thread_suspend_count_lock_, - Locks::trace_lock_); - static void Stop() LOCKS_EXCLUDED(Locks::trace_lock_); + LOCKS_EXCLUDED(Locks::mutator_lock_, + Locks::thread_list_lock_, + Locks::thread_suspend_count_lock_, + Locks::trace_lock_); + static void Stop() + LOCKS_EXCLUDED(Locks::mutator_lock_, + Locks::thread_list_lock_, + Locks::trace_lock_); static void Shutdown() LOCKS_EXCLUDED(Locks::trace_lock_); static TracingMode GetMethodTracingMode() LOCKS_EXCLUDED(Locks::trace_lock_); diff --git a/test/304-method-tracing/expected.txt b/test/304-method-tracing/expected.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/304-method-tracing/expected.txt diff --git a/test/304-method-tracing/info.txt b/test/304-method-tracing/info.txt new file mode 100644 index 0000000000..d3154e6157 --- /dev/null +++ b/test/304-method-tracing/info.txt @@ -0,0 +1 @@ +Test method tracing from command-line. diff --git a/test/304-method-tracing/run b/test/304-method-tracing/run new file mode 100755 index 0000000000..7bd1895fa2 --- /dev/null +++ b/test/304-method-tracing/run @@ -0,0 +1,18 @@ +#!/bin/bash +# +# Copyright (C) 2014 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Runs the test with method tracing enabled. +exec ${RUN} "$@" --runtime-option -Xmethod-trace --runtime-option -Xmethod-trace-file:${DEX_LOCATION}/trace.bin diff --git a/test/304-method-tracing/src/Main.java b/test/304-method-tracing/src/Main.java new file mode 100644 index 0000000000..25cee6d254 --- /dev/null +++ b/test/304-method-tracing/src/Main.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.ArrayList; + +public class Main { + static class ThreadRunnable implements Runnable { + public void run() { + for (int i = 0; i < 1000; ++i) { + doNothing(); + } + } + + private void doNothing() {} + } + + public static void main(String[] args) { + ArrayList<Thread> threads = new ArrayList<Thread>(); + for (int i = 0; i < 10; ++i) { + threads.add(new Thread(new ThreadRunnable(), "TestThread-" + i)); + } + + for (Thread t : threads) { + t.start(); + } + + for (Thread t : threads) { + try { + t.join(); + } catch (InterruptedException e) { + System.out.println("Thread " + t.getName() + " has been interrupted"); + } + } + } +} |