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