blob: 00d4144415865a597013ef6c503cca81e73e5581 [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
Andreas Gampeeafaf572017-01-20 12:34:15 -080034#include "android-base/strings.h"
Andreas Gampeaf13ab92017-01-11 20:57:40 -080035#include "art_field.h"
36#include "art_jvmti.h"
37#include "base/logging.h"
38#include "base/mutex.h"
Andreas Gampeeafaf572017-01-20 12:34:15 -080039#include "events-inl.h"
Andreas Gampef26bf2d2017-01-13 16:47:14 -080040#include "gc/system_weak.h"
41#include "gc_root-inl.h"
Andreas Gampeaf13ab92017-01-11 20:57:40 -080042#include "jni_internal.h"
43#include "mirror/class.h"
44#include "mirror/object-inl.h"
45#include "mirror/string.h"
46#include "obj_ptr.h"
Andreas Gampef26bf2d2017-01-13 16:47:14 -080047#include "runtime.h"
Andreas Gampeeafaf572017-01-20 12:34:15 -080048#include "runtime_callbacks.h"
49#include "ScopedLocalRef.h"
Andreas Gampeaf13ab92017-01-11 20:57:40 -080050#include "scoped_thread_state_change-inl.h"
51#include "thread-inl.h"
Andreas Gampe85807442017-01-13 14:40:58 -080052#include "thread_list.h"
Andreas Gampeaf13ab92017-01-11 20:57:40 -080053#include "well_known_classes.h"
54
55namespace openjdkjvmti {
56
Andreas Gampeeafaf572017-01-20 12:34:15 -080057struct ThreadCallback : public art::ThreadLifecycleCallback, public art::RuntimePhaseCallback {
58 jthread GetThreadObject(art::Thread* self) REQUIRES_SHARED(art::Locks::mutator_lock_) {
59 if (self->GetPeer() == nullptr) {
60 return nullptr;
61 }
62 return self->GetJniEnv()->AddLocalReference<jthread>(self->GetPeer());
63 }
Andreas Gampe983c1752017-01-23 19:46:56 -080064 template <ArtJvmtiEvent kEvent>
65 void Post(art::Thread* self) REQUIRES_SHARED(art::Locks::mutator_lock_) {
Andreas Gampeeafaf572017-01-20 12:34:15 -080066 DCHECK_EQ(self, art::Thread::Current());
67 ScopedLocalRef<jthread> thread(self->GetJniEnv(), GetThreadObject(self));
Andreas Gampee6377462017-01-20 17:37:50 -080068 art::ScopedThreadSuspension sts(self, art::ThreadState::kNative);
Andreas Gampe983c1752017-01-23 19:46:56 -080069 event_handler->DispatchEvent<kEvent>(self,
70 reinterpret_cast<JNIEnv*>(self->GetJniEnv()),
71 thread.get());
Andreas Gampeeafaf572017-01-20 12:34:15 -080072 }
73
74 void ThreadStart(art::Thread* self) OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
75 if (!started) {
76 // Runtime isn't started. We only expect at most the signal handler or JIT threads to be
77 // started here.
78 if (art::kIsDebugBuild) {
79 std::string name;
80 self->GetThreadName(name);
81 if (name != "Signal Catcher" && !android::base::StartsWith(name, "Jit thread pool")) {
82 LOG(FATAL) << "Unexpected thread before start: " << name;
83 }
84 }
85 return;
86 }
Andreas Gampe983c1752017-01-23 19:46:56 -080087 Post<ArtJvmtiEvent::kThreadStart>(self);
Andreas Gampeeafaf572017-01-20 12:34:15 -080088 }
89
90 void ThreadDeath(art::Thread* self) OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
Andreas Gampe983c1752017-01-23 19:46:56 -080091 Post<ArtJvmtiEvent::kThreadEnd>(self);
Andreas Gampeeafaf572017-01-20 12:34:15 -080092 }
93
94 void NextRuntimePhase(RuntimePhase phase) OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
95 if (phase == RuntimePhase::kInit) {
96 // We moved to VMInit. Report the main thread as started (it was attached early, and must
97 // not be reported until Init.
98 started = true;
Andreas Gampe983c1752017-01-23 19:46:56 -080099 Post<ArtJvmtiEvent::kThreadStart>(art::Thread::Current());
Andreas Gampeeafaf572017-01-20 12:34:15 -0800100 }
101 }
102
103 EventHandler* event_handler = nullptr;
104 bool started = false;
105};
106
107ThreadCallback gThreadCallback;
108
109void ThreadUtil::Register(EventHandler* handler) {
110 art::Runtime* runtime = art::Runtime::Current();
111
112 gThreadCallback.started = runtime->IsStarted();
113 gThreadCallback.event_handler = handler;
114
115 art::ScopedThreadStateChange stsc(art::Thread::Current(),
116 art::ThreadState::kWaitingForDebuggerToAttach);
117 art::ScopedSuspendAll ssa("Add thread callback");
118 runtime->GetRuntimeCallbacks()->AddThreadLifecycleCallback(&gThreadCallback);
119 runtime->GetRuntimeCallbacks()->AddRuntimePhaseCallback(&gThreadCallback);
120}
121
122void ThreadUtil::Unregister() {
123 art::ScopedThreadStateChange stsc(art::Thread::Current(),
124 art::ThreadState::kWaitingForDebuggerToAttach);
125 art::ScopedSuspendAll ssa("Remove thread callback");
126 art::Runtime* runtime = art::Runtime::Current();
127 runtime->GetRuntimeCallbacks()->RemoveThreadLifecycleCallback(&gThreadCallback);
128 runtime->GetRuntimeCallbacks()->RemoveRuntimePhaseCallback(&gThreadCallback);
129}
130
Andreas Gampeaf13ab92017-01-11 20:57:40 -0800131jvmtiError ThreadUtil::GetCurrentThread(jvmtiEnv* env ATTRIBUTE_UNUSED, jthread* thread_ptr) {
132 art::Thread* self = art::Thread::Current();
133
134 art::ScopedObjectAccess soa(self);
135
136 jthread thread_peer;
137 if (self->IsStillStarting()) {
138 thread_peer = nullptr;
139 } else {
140 thread_peer = soa.AddLocalReference<jthread>(self->GetPeer());
141 }
142
143 *thread_ptr = thread_peer;
144 return ERR(NONE);
145}
146
147// Read the context classloader from a Java thread object. This is a lazy implementation
148// that assumes GetThreadInfo isn't called too often. If we instead cache the ArtField,
149// we will have to add synchronization as this can't be cached on startup (which is
150// potentially runtime startup).
151static art::ObjPtr<art::mirror::Object> GetContextClassLoader(art::ObjPtr<art::mirror::Object> peer)
152 REQUIRES_SHARED(art::Locks::mutator_lock_) {
153 if (peer == nullptr) {
154 return nullptr;
155 }
156 art::ObjPtr<art::mirror::Class> klass = peer->GetClass();
157 art::ArtField* cc_field = klass->FindDeclaredInstanceField("contextClassLoader",
158 "Ljava/lang/ClassLoader;");
159 CHECK(cc_field != nullptr);
160 return cc_field->GetObject(peer);
161}
162
163// Get the native thread. The spec says a null object denotes the current thread.
164static art::Thread* GetNativeThread(jthread thread,
165 const art::ScopedObjectAccessAlreadyRunnable& soa)
166 REQUIRES_SHARED(art::Locks::mutator_lock_) {
167 if (thread == nullptr) {
168 return art::Thread::Current();
169 }
170
171 art::MutexLock mu(soa.Self(), *art::Locks::thread_list_lock_);
172 return art::Thread::FromManagedThread(soa, thread);
173}
174
175jvmtiError ThreadUtil::GetThreadInfo(jvmtiEnv* env, jthread thread, jvmtiThreadInfo* info_ptr) {
176 if (info_ptr == nullptr) {
177 return ERR(NULL_POINTER);
178 }
179
180 art::ScopedObjectAccess soa(art::Thread::Current());
181
182 art::Thread* self = GetNativeThread(thread, soa);
183 if (self == nullptr && thread == nullptr) {
184 return ERR(INVALID_THREAD);
185 }
186
187 JvmtiUniquePtr name_uptr;
188 if (self != nullptr) {
189 // Have a native thread object, this thread is alive.
190 std::string name;
191 self->GetThreadName(name);
192 jvmtiError name_result = CopyString(
193 env, name.c_str(), reinterpret_cast<unsigned char**>(&info_ptr->name));
194 if (name_result != ERR(NONE)) {
195 return name_result;
196 }
197 name_uptr = MakeJvmtiUniquePtr(env, info_ptr->name);
198
199 info_ptr->priority = self->GetNativePriority();
200
201 info_ptr->is_daemon = self->IsDaemon();
202
Andreas Gampe202f85a2017-02-06 10:23:26 -0800203 art::ObjPtr<art::mirror::Object> peer = self->GetPeerFromOtherThread();
Andreas Gampeaf13ab92017-01-11 20:57:40 -0800204
205 // ThreadGroup.
206 if (peer != nullptr) {
207 art::ArtField* f = art::jni::DecodeArtField(art::WellKnownClasses::java_lang_Thread_group);
208 CHECK(f != nullptr);
209 art::ObjPtr<art::mirror::Object> group = f->GetObject(peer);
210 info_ptr->thread_group = group == nullptr
211 ? nullptr
212 : soa.AddLocalReference<jthreadGroup>(group);
213 } else {
214 info_ptr->thread_group = nullptr;
215 }
216
217 // Context classloader.
218 art::ObjPtr<art::mirror::Object> ccl = GetContextClassLoader(peer);
219 info_ptr->context_class_loader = ccl == nullptr
220 ? nullptr
221 : soa.AddLocalReference<jobject>(ccl);
222 } else {
223 // Only the peer. This thread has either not been started, or is dead. Read things from
224 // the Java side.
225 art::ObjPtr<art::mirror::Object> peer = soa.Decode<art::mirror::Object>(thread);
226
227 // Name.
228 {
229 art::ArtField* f = art::jni::DecodeArtField(art::WellKnownClasses::java_lang_Thread_name);
230 CHECK(f != nullptr);
231 art::ObjPtr<art::mirror::Object> name = f->GetObject(peer);
232 std::string name_cpp;
233 const char* name_cstr;
234 if (name != nullptr) {
235 name_cpp = name->AsString()->ToModifiedUtf8();
236 name_cstr = name_cpp.c_str();
237 } else {
238 name_cstr = "";
239 }
240 jvmtiError name_result = CopyString(
241 env, name_cstr, reinterpret_cast<unsigned char**>(&info_ptr->name));
242 if (name_result != ERR(NONE)) {
243 return name_result;
244 }
245 name_uptr = MakeJvmtiUniquePtr(env, info_ptr->name);
246 }
247
248 // Priority.
249 {
250 art::ArtField* f = art::jni::DecodeArtField(art::WellKnownClasses::java_lang_Thread_priority);
251 CHECK(f != nullptr);
252 info_ptr->priority = static_cast<jint>(f->GetInt(peer));
253 }
254
255 // Daemon.
256 {
257 art::ArtField* f = art::jni::DecodeArtField(art::WellKnownClasses::java_lang_Thread_daemon);
258 CHECK(f != nullptr);
259 info_ptr->is_daemon = f->GetBoolean(peer) == 0 ? JNI_FALSE : JNI_TRUE;
260 }
261
262 // ThreadGroup.
263 {
264 art::ArtField* f = art::jni::DecodeArtField(art::WellKnownClasses::java_lang_Thread_group);
265 CHECK(f != nullptr);
266 art::ObjPtr<art::mirror::Object> group = f->GetObject(peer);
267 info_ptr->thread_group = group == nullptr
268 ? nullptr
269 : soa.AddLocalReference<jthreadGroup>(group);
270 }
271
272 // Context classloader.
273 art::ObjPtr<art::mirror::Object> ccl = GetContextClassLoader(peer);
274 info_ptr->context_class_loader = ccl == nullptr
275 ? nullptr
276 : soa.AddLocalReference<jobject>(ccl);
277 }
278
279 name_uptr.release();
280
281 return ERR(NONE);
282}
283
Andreas Gampe72c19832017-01-12 13:22:16 -0800284// Return the thread's (or current thread, if null) thread state. Return kStarting in case
285// there's no native counterpart (thread hasn't been started, yet, or is dead).
286static art::ThreadState GetNativeThreadState(jthread thread,
287 const art::ScopedObjectAccessAlreadyRunnable& soa,
288 art::Thread** native_thread)
289 REQUIRES_SHARED(art::Locks::mutator_lock_) {
290 art::Thread* self = nullptr;
291 art::MutexLock mu(soa.Self(), *art::Locks::thread_list_lock_);
292 if (thread == nullptr) {
293 self = art::Thread::Current();
294 } else {
295 self = art::Thread::FromManagedThread(soa, thread);
296 }
297 *native_thread = self;
298 if (self == nullptr || self->IsStillStarting()) {
299 return art::ThreadState::kStarting;
300 }
301 return self->GetState();
302}
303
304static jint GetJvmtiThreadStateFromInternal(art::ThreadState internal_thread_state) {
305 jint jvmti_state = JVMTI_THREAD_STATE_ALIVE;
306
307 if (internal_thread_state == art::ThreadState::kSuspended) {
308 jvmti_state |= JVMTI_THREAD_STATE_SUSPENDED;
309 // Note: We do not have data about the previous state. Otherwise we should load the previous
310 // state here.
311 }
312
313 if (internal_thread_state == art::ThreadState::kNative) {
314 jvmti_state |= JVMTI_THREAD_STATE_IN_NATIVE;
315 }
316
317 if (internal_thread_state == art::ThreadState::kRunnable ||
318 internal_thread_state == art::ThreadState::kWaitingWeakGcRootRead ||
319 internal_thread_state == art::ThreadState::kSuspended) {
320 jvmti_state |= JVMTI_THREAD_STATE_RUNNABLE;
321 } else if (internal_thread_state == art::ThreadState::kBlocked) {
322 jvmti_state |= JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER;
323 } else {
324 // Should be in waiting state.
325 jvmti_state |= JVMTI_THREAD_STATE_WAITING;
326
327 if (internal_thread_state == art::ThreadState::kTimedWaiting ||
328 internal_thread_state == art::ThreadState::kSleeping) {
329 jvmti_state |= JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT;
330 } else {
331 jvmti_state |= JVMTI_THREAD_STATE_WAITING_INDEFINITELY;
332 }
333
334 if (internal_thread_state == art::ThreadState::kSleeping) {
335 jvmti_state |= JVMTI_THREAD_STATE_SLEEPING;
336 }
337
338 if (internal_thread_state == art::ThreadState::kTimedWaiting ||
339 internal_thread_state == art::ThreadState::kWaiting) {
340 jvmti_state |= JVMTI_THREAD_STATE_IN_OBJECT_WAIT;
341 }
342
343 // TODO: PARKED. We'll have to inspect the stack.
344 }
345
346 return jvmti_state;
347}
348
349static jint GetJavaStateFromInternal(art::ThreadState internal_thread_state) {
350 switch (internal_thread_state) {
351 case art::ThreadState::kTerminated:
352 return JVMTI_JAVA_LANG_THREAD_STATE_TERMINATED;
353
354 case art::ThreadState::kRunnable:
355 case art::ThreadState::kNative:
356 case art::ThreadState::kWaitingWeakGcRootRead:
357 case art::ThreadState::kSuspended:
358 return JVMTI_JAVA_LANG_THREAD_STATE_RUNNABLE;
359
360 case art::ThreadState::kTimedWaiting:
361 case art::ThreadState::kSleeping:
362 return JVMTI_JAVA_LANG_THREAD_STATE_TIMED_WAITING;
363
364 case art::ThreadState::kBlocked:
365 return JVMTI_JAVA_LANG_THREAD_STATE_BLOCKED;
366
367 case art::ThreadState::kStarting:
368 return JVMTI_JAVA_LANG_THREAD_STATE_NEW;
369
370 case art::ThreadState::kWaiting:
371 case art::ThreadState::kWaitingForGcToComplete:
372 case art::ThreadState::kWaitingPerformingGc:
373 case art::ThreadState::kWaitingForCheckPointsToRun:
374 case art::ThreadState::kWaitingForDebuggerSend:
375 case art::ThreadState::kWaitingForDebuggerToAttach:
376 case art::ThreadState::kWaitingInMainDebuggerLoop:
377 case art::ThreadState::kWaitingForDebuggerSuspension:
378 case art::ThreadState::kWaitingForDeoptimization:
379 case art::ThreadState::kWaitingForGetObjectsAllocated:
380 case art::ThreadState::kWaitingForJniOnLoad:
381 case art::ThreadState::kWaitingForSignalCatcherOutput:
382 case art::ThreadState::kWaitingInMainSignalCatcherLoop:
383 case art::ThreadState::kWaitingForMethodTracingStart:
384 case art::ThreadState::kWaitingForVisitObjects:
385 case art::ThreadState::kWaitingForGcThreadFlip:
386 return JVMTI_JAVA_LANG_THREAD_STATE_WAITING;
387 }
388 LOG(FATAL) << "Unreachable";
389 UNREACHABLE();
390}
391
392jvmtiError ThreadUtil::GetThreadState(jvmtiEnv* env ATTRIBUTE_UNUSED,
393 jthread thread,
394 jint* thread_state_ptr) {
395 if (thread_state_ptr == nullptr) {
396 return ERR(NULL_POINTER);
397 }
398
399 art::ScopedObjectAccess soa(art::Thread::Current());
400 art::Thread* native_thread = nullptr;
401 art::ThreadState internal_thread_state = GetNativeThreadState(thread, soa, &native_thread);
402
403 if (internal_thread_state == art::ThreadState::kStarting) {
404 if (thread == nullptr) {
405 // No native thread, and no Java thread? We must be starting up. Report as wrong phase.
406 return ERR(WRONG_PHASE);
407 }
408
409 // Need to read the Java "started" field to know whether this is starting or terminated.
410 art::ObjPtr<art::mirror::Object> peer = soa.Decode<art::mirror::Object>(thread);
411 art::ObjPtr<art::mirror::Class> klass = peer->GetClass();
412 art::ArtField* started_field = klass->FindDeclaredInstanceField("started", "Z");
413 CHECK(started_field != nullptr);
414 bool started = started_field->GetBoolean(peer) != 0;
415 constexpr jint kStartedState = JVMTI_JAVA_LANG_THREAD_STATE_NEW;
416 constexpr jint kTerminatedState = JVMTI_THREAD_STATE_TERMINATED |
417 JVMTI_JAVA_LANG_THREAD_STATE_TERMINATED;
418 *thread_state_ptr = started ? kTerminatedState : kStartedState;
419 return ERR(NONE);
420 }
421 DCHECK(native_thread != nullptr);
422
423 // Translate internal thread state to JVMTI and Java state.
424 jint jvmti_state = GetJvmtiThreadStateFromInternal(internal_thread_state);
425 if (native_thread->IsInterrupted()) {
426 jvmti_state |= JVMTI_THREAD_STATE_INTERRUPTED;
427 }
428
429 // Java state is derived from nativeGetState.
430 // Note: Our implementation assigns "runnable" to suspended. As such, we will have slightly
431 // different mask. However, this is for consistency with the Java view.
432 jint java_state = GetJavaStateFromInternal(internal_thread_state);
433
434 *thread_state_ptr = jvmti_state | java_state;
435
436 return ERR(NONE);
437}
438
Andreas Gampe85807442017-01-13 14:40:58 -0800439jvmtiError ThreadUtil::GetAllThreads(jvmtiEnv* env,
440 jint* threads_count_ptr,
441 jthread** threads_ptr) {
442 if (threads_count_ptr == nullptr || threads_ptr == nullptr) {
443 return ERR(NULL_POINTER);
444 }
445
446 art::Thread* current = art::Thread::Current();
447
448 art::ScopedObjectAccess soa(current);
449
450 art::MutexLock mu(current, *art::Locks::thread_list_lock_);
451 std::list<art::Thread*> thread_list = art::Runtime::Current()->GetThreadList()->GetList();
452
453 std::vector<art::ObjPtr<art::mirror::Object>> peers;
454
455 for (art::Thread* thread : thread_list) {
456 // Skip threads that are still starting.
457 if (thread->IsStillStarting()) {
458 continue;
459 }
460
Andreas Gampe202f85a2017-02-06 10:23:26 -0800461 art::ObjPtr<art::mirror::Object> peer = thread->GetPeerFromOtherThread();
Andreas Gampe85807442017-01-13 14:40:58 -0800462 if (peer != nullptr) {
463 peers.push_back(peer);
464 }
465 }
466
467 if (peers.empty()) {
468 *threads_count_ptr = 0;
469 *threads_ptr = nullptr;
470 } else {
471 unsigned char* data;
472 jvmtiError data_result = env->Allocate(peers.size() * sizeof(jthread), &data);
473 if (data_result != ERR(NONE)) {
474 return data_result;
475 }
476 jthread* threads = reinterpret_cast<jthread*>(data);
477 for (size_t i = 0; i != peers.size(); ++i) {
478 threads[i] = soa.AddLocalReference<jthread>(peers[i]);
479 }
480
481 *threads_count_ptr = static_cast<jint>(peers.size());
482 *threads_ptr = threads;
483 }
Andreas Gampef26bf2d2017-01-13 16:47:14 -0800484 return ERR(NONE);
485}
Andreas Gampe85807442017-01-13 14:40:58 -0800486
Andreas Gampef26bf2d2017-01-13 16:47:14 -0800487jvmtiError ThreadUtil::SetThreadLocalStorage(jvmtiEnv* env ATTRIBUTE_UNUSED,
488 jthread thread,
489 const void* data) {
490 art::ScopedObjectAccess soa(art::Thread::Current());
491 art::Thread* self = GetNativeThread(thread, soa);
492 if (self == nullptr && thread == nullptr) {
493 return ERR(INVALID_THREAD);
494 }
495 if (self == nullptr) {
496 return ERR(THREAD_NOT_ALIVE);
497 }
498
499 self->SetCustomTLS(data);
500
501 return ERR(NONE);
502}
503
504jvmtiError ThreadUtil::GetThreadLocalStorage(jvmtiEnv* env ATTRIBUTE_UNUSED,
505 jthread thread,
506 void** data_ptr) {
507 if (data_ptr == nullptr) {
508 return ERR(NULL_POINTER);
509 }
510
511 art::ScopedObjectAccess soa(art::Thread::Current());
512 art::Thread* self = GetNativeThread(thread, soa);
513 if (self == nullptr && thread == nullptr) {
514 return ERR(INVALID_THREAD);
515 }
516 if (self == nullptr) {
517 return ERR(THREAD_NOT_ALIVE);
518 }
519
520 *data_ptr = const_cast<void*>(self->GetCustomTLS());
Andreas Gampe85807442017-01-13 14:40:58 -0800521 return ERR(NONE);
522}
523
Andreas Gampe732b0ac2017-01-18 15:23:39 -0800524struct AgentData {
525 const void* arg;
526 jvmtiStartFunction proc;
527 jthread thread;
528 JavaVM* java_vm;
529 jvmtiEnv* jvmti_env;
530 jint priority;
531};
532
533static void* AgentCallback(void* arg) {
534 std::unique_ptr<AgentData> data(reinterpret_cast<AgentData*>(arg));
535 CHECK(data->thread != nullptr);
536
537 // We already have a peer. So call our special Attach function.
538 art::Thread* self = art::Thread::Attach("JVMTI Agent thread", true, data->thread);
539 CHECK(self != nullptr);
540 // The name in Attach() is only for logging. Set the thread name. This is important so
541 // that the thread is no longer seen as starting up.
542 {
543 art::ScopedObjectAccess soa(self);
544 self->SetThreadName("JVMTI Agent thread");
545 }
546
547 // Release the peer.
548 JNIEnv* env = self->GetJniEnv();
549 env->DeleteGlobalRef(data->thread);
550 data->thread = nullptr;
551
552 // Run the agent code.
553 data->proc(data->jvmti_env, env, const_cast<void*>(data->arg));
554
555 // Detach the thread.
556 int detach_result = data->java_vm->DetachCurrentThread();
557 CHECK_EQ(detach_result, 0);
558
559 return nullptr;
560}
561
562jvmtiError ThreadUtil::RunAgentThread(jvmtiEnv* jvmti_env,
563 jthread thread,
564 jvmtiStartFunction proc,
565 const void* arg,
566 jint priority) {
567 if (priority < JVMTI_THREAD_MIN_PRIORITY || priority > JVMTI_THREAD_MAX_PRIORITY) {
568 return ERR(INVALID_PRIORITY);
569 }
570 JNIEnv* env = art::Thread::Current()->GetJniEnv();
571 if (thread == nullptr || !env->IsInstanceOf(thread, art::WellKnownClasses::java_lang_Thread)) {
572 return ERR(INVALID_THREAD);
573 }
574 if (proc == nullptr) {
575 return ERR(NULL_POINTER);
576 }
577
578 std::unique_ptr<AgentData> data(new AgentData);
579 data->arg = arg;
580 data->proc = proc;
581 // We need a global ref for Java objects, as local refs will be invalid.
582 data->thread = env->NewGlobalRef(thread);
583 data->java_vm = art::Runtime::Current()->GetJavaVM();
584 data->jvmti_env = jvmti_env;
585 data->priority = priority;
586
587 pthread_t pthread;
588 int pthread_create_result = pthread_create(&pthread,
589 nullptr,
590 &AgentCallback,
591 reinterpret_cast<void*>(data.get()));
592 if (pthread_create_result != 0) {
593 return ERR(INTERNAL);
594 }
595 data.release();
596
597 return ERR(NONE);
598}
599
Andreas Gampeaf13ab92017-01-11 20:57:40 -0800600} // namespace openjdkjvmti