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