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