blob: 04a53834a44dd02a890942c00c71679007cabba8 [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
202} // namespace openjdkjvmti