ti_threadgroup.cc revision d18d9e2a94445d4b42e4bc6f0e642e6f76b4706d
1/* 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_threadgroup.h" 33 34#include "art_field.h" 35#include "art_jvmti.h" 36#include "base/logging.h" 37#include "base/macros.h" 38#include "base/mutex.h" 39#include "handle_scope-inl.h" 40#include "jni_internal.h" 41#include "mirror/class.h" 42#include "mirror/object-inl.h" 43#include "mirror/string.h" 44#include "obj_ptr.h" 45#include "object_lock.h" 46#include "runtime.h" 47#include "scoped_thread_state_change-inl.h" 48#include "thread-inl.h" 49#include "thread_list.h" 50#include "well_known_classes.h" 51 52namespace openjdkjvmti { 53 54 55jvmtiError ThreadGroupUtil::GetTopThreadGroups(jvmtiEnv* env, 56 jint* group_count_ptr, 57 jthreadGroup** groups_ptr) { 58 // We only have a single top group. So we can take the current thread and move upwards. 59 if (group_count_ptr == nullptr || groups_ptr == nullptr) { 60 return ERR(NULL_POINTER); 61 } 62 63 art::Runtime* runtime = art::Runtime::Current(); 64 if (runtime == nullptr) { 65 // Must be starting the runtime, or dying. 66 return ERR(WRONG_PHASE); 67 } 68 69 jobject sys_thread_group = runtime->GetSystemThreadGroup(); 70 if (sys_thread_group == nullptr) { 71 // Seems we're still starting up. 72 return ERR(WRONG_PHASE); 73 } 74 75 unsigned char* data; 76 jvmtiError result = env->Allocate(sizeof(jthreadGroup), &data); 77 if (result != ERR(NONE)) { 78 return result; 79 } 80 81 jthreadGroup* groups = reinterpret_cast<jthreadGroup*>(data); 82 *groups = 83 reinterpret_cast<JNIEnv*>(art::Thread::Current()->GetJniEnv())->NewLocalRef(sys_thread_group); 84 *groups_ptr = groups; 85 *group_count_ptr = 1; 86 87 return ERR(NONE); 88} 89 90jvmtiError ThreadGroupUtil::GetThreadGroupInfo(jvmtiEnv* env, 91 jthreadGroup group, 92 jvmtiThreadGroupInfo* info_ptr) { 93 if (group == nullptr) { 94 return ERR(INVALID_THREAD_GROUP); 95 } 96 97 art::ScopedObjectAccess soa(art::Thread::Current()); 98 if (soa.Env()->IsInstanceOf(group, art::WellKnownClasses::java_lang_ThreadGroup) == JNI_FALSE) { 99 return ERR(INVALID_THREAD_GROUP); 100 } 101 102 art::ObjPtr<art::mirror::Object> obj = soa.Decode<art::mirror::Object>(group); 103 104 // Do the name first. It's the only thing that can fail. 105 { 106 art::ArtField* name_field = 107 art::jni::DecodeArtField(art::WellKnownClasses::java_lang_ThreadGroup_name); 108 CHECK(name_field != nullptr); 109 art::ObjPtr<art::mirror::String> name_obj = 110 art::ObjPtr<art::mirror::String>::DownCast(name_field->GetObject(obj)); 111 std::string tmp_str; 112 const char* tmp_cstr; 113 if (name_obj == nullptr) { 114 tmp_cstr = ""; 115 } else { 116 tmp_str = name_obj->ToModifiedUtf8(); 117 tmp_cstr = tmp_str.c_str(); 118 } 119 jvmtiError result = 120 CopyString(env, tmp_cstr, reinterpret_cast<unsigned char**>(&info_ptr->name)); 121 if (result != ERR(NONE)) { 122 return result; 123 } 124 } 125 126 // Parent. 127 { 128 art::ArtField* parent_field = 129 art::jni::DecodeArtField(art::WellKnownClasses::java_lang_ThreadGroup_parent); 130 CHECK(parent_field != nullptr); 131 art::ObjPtr<art::mirror::Object> parent_group = parent_field->GetObject(obj); 132 info_ptr->parent = parent_group == nullptr 133 ? nullptr 134 : soa.AddLocalReference<jthreadGroup>(parent_group); 135 } 136 137 // Max priority. 138 { 139 art::ArtField* prio_field = obj->GetClass()->FindDeclaredInstanceField("maxPriority", "I"); 140 CHECK(prio_field != nullptr); 141 info_ptr->max_priority = static_cast<jint>(prio_field->GetInt(obj)); 142 } 143 144 // Daemon. 145 { 146 art::ArtField* daemon_field = obj->GetClass()->FindDeclaredInstanceField("daemon", "Z"); 147 CHECK(daemon_field != nullptr); 148 info_ptr->is_daemon = daemon_field->GetBoolean(obj) == 0 ? JNI_FALSE : JNI_TRUE; 149 } 150 151 return ERR(NONE); 152} 153 154 155static bool IsInDesiredThreadGroup(art::Handle<art::mirror::Object> desired_thread_group, 156 art::ObjPtr<art::mirror::Object> peer) 157 REQUIRES_SHARED(art::Locks::mutator_lock_) { 158 CHECK(desired_thread_group.Get() != nullptr); 159 160 art::ArtField* thread_group_field = 161 art::jni::DecodeArtField(art::WellKnownClasses::java_lang_Thread_group); 162 DCHECK(thread_group_field != nullptr); 163 art::ObjPtr<art::mirror::Object> group = thread_group_field->GetObject(peer); 164 return (group == desired_thread_group.Get()); 165} 166 167static void GetThreads(art::Handle<art::mirror::Object> thread_group, 168 std::vector<art::ObjPtr<art::mirror::Object>>* thread_peers) 169 REQUIRES_SHARED(art::Locks::mutator_lock_) REQUIRES(!art::Locks::thread_list_lock_) { 170 CHECK(thread_group.Get() != nullptr); 171 172 art::MutexLock mu(art::Thread::Current(), *art::Locks::thread_list_lock_); 173 for (art::Thread* t : art::Runtime::Current()->GetThreadList()->GetList()) { 174 if (t->IsStillStarting()) { 175 continue; 176 } 177 art::ObjPtr<art::mirror::Object> peer = t->GetPeer(); 178 if (peer == nullptr) { 179 continue; 180 } 181 if (IsInDesiredThreadGroup(thread_group, peer)) { 182 thread_peers->push_back(peer); 183 } 184 } 185} 186 187static void GetChildThreadGroups(art::Handle<art::mirror::Object> thread_group, 188 std::vector<art::ObjPtr<art::mirror::Object>>* thread_groups) 189 REQUIRES_SHARED(art::Locks::mutator_lock_) { 190 CHECK(thread_group.Get() != nullptr); 191 192 // Get the ThreadGroup[] "groups" out of this thread group... 193 art::ArtField* groups_field = 194 art::jni::DecodeArtField(art::WellKnownClasses::java_lang_ThreadGroup_groups); 195 art::ObjPtr<art::mirror::Object> groups_array = groups_field->GetObject(thread_group.Get()); 196 197 if (groups_array == nullptr) { 198 return; 199 } 200 CHECK(groups_array->IsObjectArray()); 201 202 art::ObjPtr<art::mirror::ObjectArray<art::mirror::Object>> groups_array_as_array = 203 groups_array->AsObjectArray<art::mirror::Object>(); 204 205 // Copy all non-null elements. 206 for (int32_t i = 0; i < groups_array_as_array->GetLength(); ++i) { 207 art::ObjPtr<art::mirror::Object> entry = groups_array_as_array->Get(i); 208 if (entry != nullptr) { 209 thread_groups->push_back(entry); 210 } 211 } 212} 213 214jvmtiError ThreadGroupUtil::GetThreadGroupChildren(jvmtiEnv* env, 215 jthreadGroup group, 216 jint* thread_count_ptr, 217 jthread** threads_ptr, 218 jint* group_count_ptr, 219 jthreadGroup** groups_ptr) { 220 if (group == nullptr) { 221 return ERR(INVALID_THREAD_GROUP); 222 } 223 224 art::ScopedObjectAccess soa(art::Thread::Current()); 225 226 if (!soa.Env()->IsInstanceOf(group, art::WellKnownClasses::java_lang_ThreadGroup)) { 227 return ERR(INVALID_THREAD_GROUP); 228 } 229 230 art::StackHandleScope<1> hs(soa.Self()); 231 art::Handle<art::mirror::Object> thread_group = hs.NewHandle( 232 soa.Decode<art::mirror::Object>(group)); 233 234 art::ObjectLock<art::mirror::Object> thread_group_lock(soa.Self(), thread_group); 235 236 std::vector<art::ObjPtr<art::mirror::Object>> thread_peers; 237 GetThreads(thread_group, &thread_peers); 238 239 std::vector<art::ObjPtr<art::mirror::Object>> thread_groups; 240 GetChildThreadGroups(thread_group, &thread_groups); 241 242 jthread* thread_data = nullptr; 243 JvmtiUniquePtr peers_uptr; 244 if (!thread_peers.empty()) { 245 unsigned char* data; 246 jvmtiError res = env->Allocate(sizeof(jthread) * thread_peers.size(), &data); 247 if (res != ERR(NONE)) { 248 return res; 249 } 250 thread_data = reinterpret_cast<jthread*>(data); 251 peers_uptr = MakeJvmtiUniquePtr(env, data); 252 } 253 254 jthreadGroup* group_data = nullptr; 255 if (!thread_groups.empty()) { 256 unsigned char* data; 257 jvmtiError res = env->Allocate(sizeof(jthreadGroup) * thread_groups.size(), &data); 258 if (res != ERR(NONE)) { 259 return res; 260 } 261 group_data = reinterpret_cast<jthreadGroup*>(data); 262 } 263 264 // Can't fail anymore from here on. 265 266 // Copy data into out buffers. 267 for (size_t i = 0; i != thread_peers.size(); ++i) { 268 thread_data[i] = soa.AddLocalReference<jthread>(thread_peers[i]); 269 } 270 for (size_t i = 0; i != thread_groups.size(); ++i) { 271 group_data[i] = soa.AddLocalReference<jthreadGroup>(thread_groups[i]); 272 } 273 274 *thread_count_ptr = static_cast<jint>(thread_peers.size()); 275 *threads_ptr = thread_data; 276 *group_count_ptr = static_cast<jint>(thread_groups.size()); 277 *groups_ptr = group_data; 278 279 // Everything's fine. 280 peers_uptr.release(); 281 282 return ERR(NONE); 283} 284 285} // namespace openjdkjvmti 286