blob: e20f5605d8a5c7aeb51f1699cb70ec7ce8addce6 [file] [log] [blame]
Andreas Gampeaf13ab92017-01-11 20:57:40 -08001/* Copyright (C) 2017 The Android Open Source Project
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3 *
4 * This file implements interfaces from the file jvmti.h. This implementation
5 * is licensed under the same terms as the file jvmti.h. The
6 * copyright and license information for the file jvmti.h follows.
7 *
8 * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
9 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
10 *
11 * This code is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License version 2 only, as
13 * published by the Free Software Foundation. Oracle designates this
14 * particular file as subject to the "Classpath" exception as provided
15 * by Oracle in the LICENSE file that accompanied this code.
16 *
17 * This code is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * version 2 for more details (a copy is included in the LICENSE file that
21 * accompanied this code).
22 *
23 * You should have received a copy of the GNU General Public License version
24 * 2 along with this work; if not, write to the Free Software Foundation,
25 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
26 *
27 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
28 * or visit www.oracle.com if you need additional information or have any
29 * questions.
30 */
31
32#include "ti_thread.h"
33
34#include "art_field.h"
35#include "art_jvmti.h"
36#include "base/logging.h"
37#include "base/mutex.h"
38#include "jni_internal.h"
39#include "mirror/class.h"
40#include "mirror/object-inl.h"
41#include "mirror/string.h"
42#include "obj_ptr.h"
43#include "scoped_thread_state_change-inl.h"
44#include "thread-inl.h"
45#include "well_known_classes.h"
46
47namespace openjdkjvmti {
48
49jvmtiError ThreadUtil::GetCurrentThread(jvmtiEnv* env ATTRIBUTE_UNUSED, jthread* thread_ptr) {
50 art::Thread* self = art::Thread::Current();
51
52 art::ScopedObjectAccess soa(self);
53
54 jthread thread_peer;
55 if (self->IsStillStarting()) {
56 thread_peer = nullptr;
57 } else {
58 thread_peer = soa.AddLocalReference<jthread>(self->GetPeer());
59 }
60
61 *thread_ptr = thread_peer;
62 return ERR(NONE);
63}
64
65// Read the context classloader from a Java thread object. This is a lazy implementation
66// that assumes GetThreadInfo isn't called too often. If we instead cache the ArtField,
67// we will have to add synchronization as this can't be cached on startup (which is
68// potentially runtime startup).
69static art::ObjPtr<art::mirror::Object> GetContextClassLoader(art::ObjPtr<art::mirror::Object> peer)
70 REQUIRES_SHARED(art::Locks::mutator_lock_) {
71 if (peer == nullptr) {
72 return nullptr;
73 }
74 art::ObjPtr<art::mirror::Class> klass = peer->GetClass();
75 art::ArtField* cc_field = klass->FindDeclaredInstanceField("contextClassLoader",
76 "Ljava/lang/ClassLoader;");
77 CHECK(cc_field != nullptr);
78 return cc_field->GetObject(peer);
79}
80
81// Get the native thread. The spec says a null object denotes the current thread.
82static art::Thread* GetNativeThread(jthread thread,
83 const art::ScopedObjectAccessAlreadyRunnable& soa)
84 REQUIRES_SHARED(art::Locks::mutator_lock_) {
85 if (thread == nullptr) {
86 return art::Thread::Current();
87 }
88
89 art::MutexLock mu(soa.Self(), *art::Locks::thread_list_lock_);
90 return art::Thread::FromManagedThread(soa, thread);
91}
92
93jvmtiError ThreadUtil::GetThreadInfo(jvmtiEnv* env, jthread thread, jvmtiThreadInfo* info_ptr) {
94 if (info_ptr == nullptr) {
95 return ERR(NULL_POINTER);
96 }
97
98 art::ScopedObjectAccess soa(art::Thread::Current());
99
100 art::Thread* self = GetNativeThread(thread, soa);
101 if (self == nullptr && thread == nullptr) {
102 return ERR(INVALID_THREAD);
103 }
104
105 JvmtiUniquePtr name_uptr;
106 if (self != nullptr) {
107 // Have a native thread object, this thread is alive.
108 std::string name;
109 self->GetThreadName(name);
110 jvmtiError name_result = CopyString(
111 env, name.c_str(), reinterpret_cast<unsigned char**>(&info_ptr->name));
112 if (name_result != ERR(NONE)) {
113 return name_result;
114 }
115 name_uptr = MakeJvmtiUniquePtr(env, info_ptr->name);
116
117 info_ptr->priority = self->GetNativePriority();
118
119 info_ptr->is_daemon = self->IsDaemon();
120
121 art::ObjPtr<art::mirror::Object> peer = self->GetPeer();
122
123 // ThreadGroup.
124 if (peer != nullptr) {
125 art::ArtField* f = art::jni::DecodeArtField(art::WellKnownClasses::java_lang_Thread_group);
126 CHECK(f != nullptr);
127 art::ObjPtr<art::mirror::Object> group = f->GetObject(peer);
128 info_ptr->thread_group = group == nullptr
129 ? nullptr
130 : soa.AddLocalReference<jthreadGroup>(group);
131 } else {
132 info_ptr->thread_group = nullptr;
133 }
134
135 // Context classloader.
136 art::ObjPtr<art::mirror::Object> ccl = GetContextClassLoader(peer);
137 info_ptr->context_class_loader = ccl == nullptr
138 ? nullptr
139 : soa.AddLocalReference<jobject>(ccl);
140 } else {
141 // Only the peer. This thread has either not been started, or is dead. Read things from
142 // the Java side.
143 art::ObjPtr<art::mirror::Object> peer = soa.Decode<art::mirror::Object>(thread);
144
145 // Name.
146 {
147 art::ArtField* f = art::jni::DecodeArtField(art::WellKnownClasses::java_lang_Thread_name);
148 CHECK(f != nullptr);
149 art::ObjPtr<art::mirror::Object> name = f->GetObject(peer);
150 std::string name_cpp;
151 const char* name_cstr;
152 if (name != nullptr) {
153 name_cpp = name->AsString()->ToModifiedUtf8();
154 name_cstr = name_cpp.c_str();
155 } else {
156 name_cstr = "";
157 }
158 jvmtiError name_result = CopyString(
159 env, name_cstr, reinterpret_cast<unsigned char**>(&info_ptr->name));
160 if (name_result != ERR(NONE)) {
161 return name_result;
162 }
163 name_uptr = MakeJvmtiUniquePtr(env, info_ptr->name);
164 }
165
166 // Priority.
167 {
168 art::ArtField* f = art::jni::DecodeArtField(art::WellKnownClasses::java_lang_Thread_priority);
169 CHECK(f != nullptr);
170 info_ptr->priority = static_cast<jint>(f->GetInt(peer));
171 }
172
173 // Daemon.
174 {
175 art::ArtField* f = art::jni::DecodeArtField(art::WellKnownClasses::java_lang_Thread_daemon);
176 CHECK(f != nullptr);
177 info_ptr->is_daemon = f->GetBoolean(peer) == 0 ? JNI_FALSE : JNI_TRUE;
178 }
179
180 // ThreadGroup.
181 {
182 art::ArtField* f = art::jni::DecodeArtField(art::WellKnownClasses::java_lang_Thread_group);
183 CHECK(f != nullptr);
184 art::ObjPtr<art::mirror::Object> group = f->GetObject(peer);
185 info_ptr->thread_group = group == nullptr
186 ? nullptr
187 : soa.AddLocalReference<jthreadGroup>(group);
188 }
189
190 // Context classloader.
191 art::ObjPtr<art::mirror::Object> ccl = GetContextClassLoader(peer);
192 info_ptr->context_class_loader = ccl == nullptr
193 ? nullptr
194 : soa.AddLocalReference<jobject>(ccl);
195 }
196
197 name_uptr.release();
198
199 return ERR(NONE);
200}
201
Andreas Gampe72c19832017-01-12 13:22:16 -0800202// Return the thread's (or current thread, if null) thread state. Return kStarting in case
203// there's no native counterpart (thread hasn't been started, yet, or is dead).
204static art::ThreadState GetNativeThreadState(jthread thread,
205 const art::ScopedObjectAccessAlreadyRunnable& soa,
206 art::Thread** native_thread)
207 REQUIRES_SHARED(art::Locks::mutator_lock_) {
208 art::Thread* self = nullptr;
209 art::MutexLock mu(soa.Self(), *art::Locks::thread_list_lock_);
210 if (thread == nullptr) {
211 self = art::Thread::Current();
212 } else {
213 self = art::Thread::FromManagedThread(soa, thread);
214 }
215 *native_thread = self;
216 if (self == nullptr || self->IsStillStarting()) {
217 return art::ThreadState::kStarting;
218 }
219 return self->GetState();
220}
221
222static jint GetJvmtiThreadStateFromInternal(art::ThreadState internal_thread_state) {
223 jint jvmti_state = JVMTI_THREAD_STATE_ALIVE;
224
225 if (internal_thread_state == art::ThreadState::kSuspended) {
226 jvmti_state |= JVMTI_THREAD_STATE_SUSPENDED;
227 // Note: We do not have data about the previous state. Otherwise we should load the previous
228 // state here.
229 }
230
231 if (internal_thread_state == art::ThreadState::kNative) {
232 jvmti_state |= JVMTI_THREAD_STATE_IN_NATIVE;
233 }
234
235 if (internal_thread_state == art::ThreadState::kRunnable ||
236 internal_thread_state == art::ThreadState::kWaitingWeakGcRootRead ||
237 internal_thread_state == art::ThreadState::kSuspended) {
238 jvmti_state |= JVMTI_THREAD_STATE_RUNNABLE;
239 } else if (internal_thread_state == art::ThreadState::kBlocked) {
240 jvmti_state |= JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER;
241 } else {
242 // Should be in waiting state.
243 jvmti_state |= JVMTI_THREAD_STATE_WAITING;
244
245 if (internal_thread_state == art::ThreadState::kTimedWaiting ||
246 internal_thread_state == art::ThreadState::kSleeping) {
247 jvmti_state |= JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT;
248 } else {
249 jvmti_state |= JVMTI_THREAD_STATE_WAITING_INDEFINITELY;
250 }
251
252 if (internal_thread_state == art::ThreadState::kSleeping) {
253 jvmti_state |= JVMTI_THREAD_STATE_SLEEPING;
254 }
255
256 if (internal_thread_state == art::ThreadState::kTimedWaiting ||
257 internal_thread_state == art::ThreadState::kWaiting) {
258 jvmti_state |= JVMTI_THREAD_STATE_IN_OBJECT_WAIT;
259 }
260
261 // TODO: PARKED. We'll have to inspect the stack.
262 }
263
264 return jvmti_state;
265}
266
267static jint GetJavaStateFromInternal(art::ThreadState internal_thread_state) {
268 switch (internal_thread_state) {
269 case art::ThreadState::kTerminated:
270 return JVMTI_JAVA_LANG_THREAD_STATE_TERMINATED;
271
272 case art::ThreadState::kRunnable:
273 case art::ThreadState::kNative:
274 case art::ThreadState::kWaitingWeakGcRootRead:
275 case art::ThreadState::kSuspended:
276 return JVMTI_JAVA_LANG_THREAD_STATE_RUNNABLE;
277
278 case art::ThreadState::kTimedWaiting:
279 case art::ThreadState::kSleeping:
280 return JVMTI_JAVA_LANG_THREAD_STATE_TIMED_WAITING;
281
282 case art::ThreadState::kBlocked:
283 return JVMTI_JAVA_LANG_THREAD_STATE_BLOCKED;
284
285 case art::ThreadState::kStarting:
286 return JVMTI_JAVA_LANG_THREAD_STATE_NEW;
287
288 case art::ThreadState::kWaiting:
289 case art::ThreadState::kWaitingForGcToComplete:
290 case art::ThreadState::kWaitingPerformingGc:
291 case art::ThreadState::kWaitingForCheckPointsToRun:
292 case art::ThreadState::kWaitingForDebuggerSend:
293 case art::ThreadState::kWaitingForDebuggerToAttach:
294 case art::ThreadState::kWaitingInMainDebuggerLoop:
295 case art::ThreadState::kWaitingForDebuggerSuspension:
296 case art::ThreadState::kWaitingForDeoptimization:
297 case art::ThreadState::kWaitingForGetObjectsAllocated:
298 case art::ThreadState::kWaitingForJniOnLoad:
299 case art::ThreadState::kWaitingForSignalCatcherOutput:
300 case art::ThreadState::kWaitingInMainSignalCatcherLoop:
301 case art::ThreadState::kWaitingForMethodTracingStart:
302 case art::ThreadState::kWaitingForVisitObjects:
303 case art::ThreadState::kWaitingForGcThreadFlip:
304 return JVMTI_JAVA_LANG_THREAD_STATE_WAITING;
305 }
306 LOG(FATAL) << "Unreachable";
307 UNREACHABLE();
308}
309
310jvmtiError ThreadUtil::GetThreadState(jvmtiEnv* env ATTRIBUTE_UNUSED,
311 jthread thread,
312 jint* thread_state_ptr) {
313 if (thread_state_ptr == nullptr) {
314 return ERR(NULL_POINTER);
315 }
316
317 art::ScopedObjectAccess soa(art::Thread::Current());
318 art::Thread* native_thread = nullptr;
319 art::ThreadState internal_thread_state = GetNativeThreadState(thread, soa, &native_thread);
320
321 if (internal_thread_state == art::ThreadState::kStarting) {
322 if (thread == nullptr) {
323 // No native thread, and no Java thread? We must be starting up. Report as wrong phase.
324 return ERR(WRONG_PHASE);
325 }
326
327 // Need to read the Java "started" field to know whether this is starting or terminated.
328 art::ObjPtr<art::mirror::Object> peer = soa.Decode<art::mirror::Object>(thread);
329 art::ObjPtr<art::mirror::Class> klass = peer->GetClass();
330 art::ArtField* started_field = klass->FindDeclaredInstanceField("started", "Z");
331 CHECK(started_field != nullptr);
332 bool started = started_field->GetBoolean(peer) != 0;
333 constexpr jint kStartedState = JVMTI_JAVA_LANG_THREAD_STATE_NEW;
334 constexpr jint kTerminatedState = JVMTI_THREAD_STATE_TERMINATED |
335 JVMTI_JAVA_LANG_THREAD_STATE_TERMINATED;
336 *thread_state_ptr = started ? kTerminatedState : kStartedState;
337 return ERR(NONE);
338 }
339 DCHECK(native_thread != nullptr);
340
341 // Translate internal thread state to JVMTI and Java state.
342 jint jvmti_state = GetJvmtiThreadStateFromInternal(internal_thread_state);
343 if (native_thread->IsInterrupted()) {
344 jvmti_state |= JVMTI_THREAD_STATE_INTERRUPTED;
345 }
346
347 // Java state is derived from nativeGetState.
348 // Note: Our implementation assigns "runnable" to suspended. As such, we will have slightly
349 // different mask. However, this is for consistency with the Java view.
350 jint java_state = GetJavaStateFromInternal(internal_thread_state);
351
352 *thread_state_ptr = jvmti_state | java_state;
353
354 return ERR(NONE);
355}
356
Andreas Gampeaf13ab92017-01-11 20:57:40 -0800357} // namespace openjdkjvmti