blob: f7f63bd19c5f11fae707f156239819a872fca280 [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"
Andreas Gampe85807442017-01-13 14:40:58 -080045#include "thread_list.h"
Andreas Gampeaf13ab92017-01-11 20:57:40 -080046#include "well_known_classes.h"
47
48namespace openjdkjvmti {
49
50jvmtiError ThreadUtil::GetCurrentThread(jvmtiEnv* env ATTRIBUTE_UNUSED, jthread* thread_ptr) {
51 art::Thread* self = art::Thread::Current();
52
53 art::ScopedObjectAccess soa(self);
54
55 jthread thread_peer;
56 if (self->IsStillStarting()) {
57 thread_peer = nullptr;
58 } else {
59 thread_peer = soa.AddLocalReference<jthread>(self->GetPeer());
60 }
61
62 *thread_ptr = thread_peer;
63 return ERR(NONE);
64}
65
66// Read the context classloader from a Java thread object. This is a lazy implementation
67// that assumes GetThreadInfo isn't called too often. If we instead cache the ArtField,
68// we will have to add synchronization as this can't be cached on startup (which is
69// potentially runtime startup).
70static art::ObjPtr<art::mirror::Object> GetContextClassLoader(art::ObjPtr<art::mirror::Object> peer)
71 REQUIRES_SHARED(art::Locks::mutator_lock_) {
72 if (peer == nullptr) {
73 return nullptr;
74 }
75 art::ObjPtr<art::mirror::Class> klass = peer->GetClass();
76 art::ArtField* cc_field = klass->FindDeclaredInstanceField("contextClassLoader",
77 "Ljava/lang/ClassLoader;");
78 CHECK(cc_field != nullptr);
79 return cc_field->GetObject(peer);
80}
81
82// Get the native thread. The spec says a null object denotes the current thread.
83static art::Thread* GetNativeThread(jthread thread,
84 const art::ScopedObjectAccessAlreadyRunnable& soa)
85 REQUIRES_SHARED(art::Locks::mutator_lock_) {
86 if (thread == nullptr) {
87 return art::Thread::Current();
88 }
89
90 art::MutexLock mu(soa.Self(), *art::Locks::thread_list_lock_);
91 return art::Thread::FromManagedThread(soa, thread);
92}
93
94jvmtiError ThreadUtil::GetThreadInfo(jvmtiEnv* env, jthread thread, jvmtiThreadInfo* info_ptr) {
95 if (info_ptr == nullptr) {
96 return ERR(NULL_POINTER);
97 }
98
99 art::ScopedObjectAccess soa(art::Thread::Current());
100
101 art::Thread* self = GetNativeThread(thread, soa);
102 if (self == nullptr && thread == nullptr) {
103 return ERR(INVALID_THREAD);
104 }
105
106 JvmtiUniquePtr name_uptr;
107 if (self != nullptr) {
108 // Have a native thread object, this thread is alive.
109 std::string name;
110 self->GetThreadName(name);
111 jvmtiError name_result = CopyString(
112 env, name.c_str(), reinterpret_cast<unsigned char**>(&info_ptr->name));
113 if (name_result != ERR(NONE)) {
114 return name_result;
115 }
116 name_uptr = MakeJvmtiUniquePtr(env, info_ptr->name);
117
118 info_ptr->priority = self->GetNativePriority();
119
120 info_ptr->is_daemon = self->IsDaemon();
121
122 art::ObjPtr<art::mirror::Object> peer = self->GetPeer();
123
124 // ThreadGroup.
125 if (peer != nullptr) {
126 art::ArtField* f = art::jni::DecodeArtField(art::WellKnownClasses::java_lang_Thread_group);
127 CHECK(f != nullptr);
128 art::ObjPtr<art::mirror::Object> group = f->GetObject(peer);
129 info_ptr->thread_group = group == nullptr
130 ? nullptr
131 : soa.AddLocalReference<jthreadGroup>(group);
132 } else {
133 info_ptr->thread_group = nullptr;
134 }
135
136 // Context classloader.
137 art::ObjPtr<art::mirror::Object> ccl = GetContextClassLoader(peer);
138 info_ptr->context_class_loader = ccl == nullptr
139 ? nullptr
140 : soa.AddLocalReference<jobject>(ccl);
141 } else {
142 // Only the peer. This thread has either not been started, or is dead. Read things from
143 // the Java side.
144 art::ObjPtr<art::mirror::Object> peer = soa.Decode<art::mirror::Object>(thread);
145
146 // Name.
147 {
148 art::ArtField* f = art::jni::DecodeArtField(art::WellKnownClasses::java_lang_Thread_name);
149 CHECK(f != nullptr);
150 art::ObjPtr<art::mirror::Object> name = f->GetObject(peer);
151 std::string name_cpp;
152 const char* name_cstr;
153 if (name != nullptr) {
154 name_cpp = name->AsString()->ToModifiedUtf8();
155 name_cstr = name_cpp.c_str();
156 } else {
157 name_cstr = "";
158 }
159 jvmtiError name_result = CopyString(
160 env, name_cstr, reinterpret_cast<unsigned char**>(&info_ptr->name));
161 if (name_result != ERR(NONE)) {
162 return name_result;
163 }
164 name_uptr = MakeJvmtiUniquePtr(env, info_ptr->name);
165 }
166
167 // Priority.
168 {
169 art::ArtField* f = art::jni::DecodeArtField(art::WellKnownClasses::java_lang_Thread_priority);
170 CHECK(f != nullptr);
171 info_ptr->priority = static_cast<jint>(f->GetInt(peer));
172 }
173
174 // Daemon.
175 {
176 art::ArtField* f = art::jni::DecodeArtField(art::WellKnownClasses::java_lang_Thread_daemon);
177 CHECK(f != nullptr);
178 info_ptr->is_daemon = f->GetBoolean(peer) == 0 ? JNI_FALSE : JNI_TRUE;
179 }
180
181 // ThreadGroup.
182 {
183 art::ArtField* f = art::jni::DecodeArtField(art::WellKnownClasses::java_lang_Thread_group);
184 CHECK(f != nullptr);
185 art::ObjPtr<art::mirror::Object> group = f->GetObject(peer);
186 info_ptr->thread_group = group == nullptr
187 ? nullptr
188 : soa.AddLocalReference<jthreadGroup>(group);
189 }
190
191 // Context classloader.
192 art::ObjPtr<art::mirror::Object> ccl = GetContextClassLoader(peer);
193 info_ptr->context_class_loader = ccl == nullptr
194 ? nullptr
195 : soa.AddLocalReference<jobject>(ccl);
196 }
197
198 name_uptr.release();
199
200 return ERR(NONE);
201}
202
Andreas Gampe72c19832017-01-12 13:22:16 -0800203// Return the thread's (or current thread, if null) thread state. Return kStarting in case
204// there's no native counterpart (thread hasn't been started, yet, or is dead).
205static art::ThreadState GetNativeThreadState(jthread thread,
206 const art::ScopedObjectAccessAlreadyRunnable& soa,
207 art::Thread** native_thread)
208 REQUIRES_SHARED(art::Locks::mutator_lock_) {
209 art::Thread* self = nullptr;
210 art::MutexLock mu(soa.Self(), *art::Locks::thread_list_lock_);
211 if (thread == nullptr) {
212 self = art::Thread::Current();
213 } else {
214 self = art::Thread::FromManagedThread(soa, thread);
215 }
216 *native_thread = self;
217 if (self == nullptr || self->IsStillStarting()) {
218 return art::ThreadState::kStarting;
219 }
220 return self->GetState();
221}
222
223static jint GetJvmtiThreadStateFromInternal(art::ThreadState internal_thread_state) {
224 jint jvmti_state = JVMTI_THREAD_STATE_ALIVE;
225
226 if (internal_thread_state == art::ThreadState::kSuspended) {
227 jvmti_state |= JVMTI_THREAD_STATE_SUSPENDED;
228 // Note: We do not have data about the previous state. Otherwise we should load the previous
229 // state here.
230 }
231
232 if (internal_thread_state == art::ThreadState::kNative) {
233 jvmti_state |= JVMTI_THREAD_STATE_IN_NATIVE;
234 }
235
236 if (internal_thread_state == art::ThreadState::kRunnable ||
237 internal_thread_state == art::ThreadState::kWaitingWeakGcRootRead ||
238 internal_thread_state == art::ThreadState::kSuspended) {
239 jvmti_state |= JVMTI_THREAD_STATE_RUNNABLE;
240 } else if (internal_thread_state == art::ThreadState::kBlocked) {
241 jvmti_state |= JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER;
242 } else {
243 // Should be in waiting state.
244 jvmti_state |= JVMTI_THREAD_STATE_WAITING;
245
246 if (internal_thread_state == art::ThreadState::kTimedWaiting ||
247 internal_thread_state == art::ThreadState::kSleeping) {
248 jvmti_state |= JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT;
249 } else {
250 jvmti_state |= JVMTI_THREAD_STATE_WAITING_INDEFINITELY;
251 }
252
253 if (internal_thread_state == art::ThreadState::kSleeping) {
254 jvmti_state |= JVMTI_THREAD_STATE_SLEEPING;
255 }
256
257 if (internal_thread_state == art::ThreadState::kTimedWaiting ||
258 internal_thread_state == art::ThreadState::kWaiting) {
259 jvmti_state |= JVMTI_THREAD_STATE_IN_OBJECT_WAIT;
260 }
261
262 // TODO: PARKED. We'll have to inspect the stack.
263 }
264
265 return jvmti_state;
266}
267
268static jint GetJavaStateFromInternal(art::ThreadState internal_thread_state) {
269 switch (internal_thread_state) {
270 case art::ThreadState::kTerminated:
271 return JVMTI_JAVA_LANG_THREAD_STATE_TERMINATED;
272
273 case art::ThreadState::kRunnable:
274 case art::ThreadState::kNative:
275 case art::ThreadState::kWaitingWeakGcRootRead:
276 case art::ThreadState::kSuspended:
277 return JVMTI_JAVA_LANG_THREAD_STATE_RUNNABLE;
278
279 case art::ThreadState::kTimedWaiting:
280 case art::ThreadState::kSleeping:
281 return JVMTI_JAVA_LANG_THREAD_STATE_TIMED_WAITING;
282
283 case art::ThreadState::kBlocked:
284 return JVMTI_JAVA_LANG_THREAD_STATE_BLOCKED;
285
286 case art::ThreadState::kStarting:
287 return JVMTI_JAVA_LANG_THREAD_STATE_NEW;
288
289 case art::ThreadState::kWaiting:
290 case art::ThreadState::kWaitingForGcToComplete:
291 case art::ThreadState::kWaitingPerformingGc:
292 case art::ThreadState::kWaitingForCheckPointsToRun:
293 case art::ThreadState::kWaitingForDebuggerSend:
294 case art::ThreadState::kWaitingForDebuggerToAttach:
295 case art::ThreadState::kWaitingInMainDebuggerLoop:
296 case art::ThreadState::kWaitingForDebuggerSuspension:
297 case art::ThreadState::kWaitingForDeoptimization:
298 case art::ThreadState::kWaitingForGetObjectsAllocated:
299 case art::ThreadState::kWaitingForJniOnLoad:
300 case art::ThreadState::kWaitingForSignalCatcherOutput:
301 case art::ThreadState::kWaitingInMainSignalCatcherLoop:
302 case art::ThreadState::kWaitingForMethodTracingStart:
303 case art::ThreadState::kWaitingForVisitObjects:
304 case art::ThreadState::kWaitingForGcThreadFlip:
305 return JVMTI_JAVA_LANG_THREAD_STATE_WAITING;
306 }
307 LOG(FATAL) << "Unreachable";
308 UNREACHABLE();
309}
310
311jvmtiError ThreadUtil::GetThreadState(jvmtiEnv* env ATTRIBUTE_UNUSED,
312 jthread thread,
313 jint* thread_state_ptr) {
314 if (thread_state_ptr == nullptr) {
315 return ERR(NULL_POINTER);
316 }
317
318 art::ScopedObjectAccess soa(art::Thread::Current());
319 art::Thread* native_thread = nullptr;
320 art::ThreadState internal_thread_state = GetNativeThreadState(thread, soa, &native_thread);
321
322 if (internal_thread_state == art::ThreadState::kStarting) {
323 if (thread == nullptr) {
324 // No native thread, and no Java thread? We must be starting up. Report as wrong phase.
325 return ERR(WRONG_PHASE);
326 }
327
328 // Need to read the Java "started" field to know whether this is starting or terminated.
329 art::ObjPtr<art::mirror::Object> peer = soa.Decode<art::mirror::Object>(thread);
330 art::ObjPtr<art::mirror::Class> klass = peer->GetClass();
331 art::ArtField* started_field = klass->FindDeclaredInstanceField("started", "Z");
332 CHECK(started_field != nullptr);
333 bool started = started_field->GetBoolean(peer) != 0;
334 constexpr jint kStartedState = JVMTI_JAVA_LANG_THREAD_STATE_NEW;
335 constexpr jint kTerminatedState = JVMTI_THREAD_STATE_TERMINATED |
336 JVMTI_JAVA_LANG_THREAD_STATE_TERMINATED;
337 *thread_state_ptr = started ? kTerminatedState : kStartedState;
338 return ERR(NONE);
339 }
340 DCHECK(native_thread != nullptr);
341
342 // Translate internal thread state to JVMTI and Java state.
343 jint jvmti_state = GetJvmtiThreadStateFromInternal(internal_thread_state);
344 if (native_thread->IsInterrupted()) {
345 jvmti_state |= JVMTI_THREAD_STATE_INTERRUPTED;
346 }
347
348 // Java state is derived from nativeGetState.
349 // Note: Our implementation assigns "runnable" to suspended. As such, we will have slightly
350 // different mask. However, this is for consistency with the Java view.
351 jint java_state = GetJavaStateFromInternal(internal_thread_state);
352
353 *thread_state_ptr = jvmti_state | java_state;
354
355 return ERR(NONE);
356}
357
Andreas Gampe85807442017-01-13 14:40:58 -0800358jvmtiError ThreadUtil::GetAllThreads(jvmtiEnv* env,
359 jint* threads_count_ptr,
360 jthread** threads_ptr) {
361 if (threads_count_ptr == nullptr || threads_ptr == nullptr) {
362 return ERR(NULL_POINTER);
363 }
364
365 art::Thread* current = art::Thread::Current();
366
367 art::ScopedObjectAccess soa(current);
368
369 art::MutexLock mu(current, *art::Locks::thread_list_lock_);
370 std::list<art::Thread*> thread_list = art::Runtime::Current()->GetThreadList()->GetList();
371
372 std::vector<art::ObjPtr<art::mirror::Object>> peers;
373
374 for (art::Thread* thread : thread_list) {
375 // Skip threads that are still starting.
376 if (thread->IsStillStarting()) {
377 continue;
378 }
379
380 art::ObjPtr<art::mirror::Object> peer = thread->GetPeer();
381 if (peer != nullptr) {
382 peers.push_back(peer);
383 }
384 }
385
386 if (peers.empty()) {
387 *threads_count_ptr = 0;
388 *threads_ptr = nullptr;
389 } else {
390 unsigned char* data;
391 jvmtiError data_result = env->Allocate(peers.size() * sizeof(jthread), &data);
392 if (data_result != ERR(NONE)) {
393 return data_result;
394 }
395 jthread* threads = reinterpret_cast<jthread*>(data);
396 for (size_t i = 0; i != peers.size(); ++i) {
397 threads[i] = soa.AddLocalReference<jthread>(peers[i]);
398 }
399
400 *threads_count_ptr = static_cast<jint>(peers.size());
401 *threads_ptr = threads;
402 }
403
404 return ERR(NONE);
405}
406
Andreas Gampeaf13ab92017-01-11 20:57:40 -0800407} // namespace openjdkjvmti