@@ -161,49 +161,83 @@ void WallClockJVMTI::timerLoop() {
161
161
// Attach to JVM as the first step
162
162
VM::attachThread (" Datadog Profiler Wallclock Sampler" );
163
163
auto collectThreads = [&](std::vector<ThreadEntry>& threads) {
164
- jvmtiEnv* jvmti = VM::jvmti ();
165
- if (jvmti == nullptr ) {
166
- return ;
167
- }
168
- JNIEnv* jni = VM::jni ();
169
-
170
- jint threads_count = 0 ;
171
- jthread* threads_ptr = nullptr ;
172
- jvmti->GetAllThreads (&threads_count, &threads_ptr);
164
+ jvmtiEnv* jvmti = VM::jvmti ();
165
+ if (jvmti == nullptr ) {
166
+ return ;
167
+ }
168
+ JNIEnv* jni = VM::jni ();
173
169
174
- bool do_filter = Profiler::instance ()->threadFilter ()->enabled ();
175
- int self = OS::threadId ();
170
+ jint threads_count = 0 ;
171
+ jthread* threads_ptr = nullptr ;
172
+ jvmti->GetAllThreads (&threads_count, &threads_ptr);
176
173
177
- for (int i = 0 ; i < threads_count; i++) {
178
- jthread thread = threads_ptr[i];
179
- if (thread != nullptr ) {
180
- VMThread* nThread = VMThread::fromJavaThread (jni, thread);
181
- if (nThread == nullptr ) {
182
- continue ;
183
- }
184
- int tid = nThread->osThreadId ();
185
- if (tid != self && (!do_filter || Profiler::instance ()->threadFilter ()->accept (tid))) {
186
- threads.push_back ({nThread, thread});
187
- }
174
+ bool do_filter = Profiler::instance ()->threadFilter ()->enabled ();
175
+ int self = OS::threadId ();
176
+ for (int i = 0 ; i < threads_count; i++) {
177
+ jthread thread = threads_ptr[i];
178
+ if (thread != nullptr ) {
179
+ VMThread* nThread = VMThread::fromJavaThread (jni, thread);
180
+ if (nThread == nullptr ) {
181
+ jni->DeleteLocalRef (thread);
182
+ continue ;
188
183
}
184
+ jint thread_state;
185
+ if (jvmti->GetThreadState (thread, &thread_state) == JVMTI_ERROR_NONE &&
186
+ (thread_state & JVMTI_THREAD_STATE_TERMINATED) == 0 ) {
187
+ int tid = VMThread::nativeThreadId (jni, thread);
188
+ if (tid != -1 && tid != self && (!do_filter || Profiler::instance ()->threadFilter ()->accept (tid))) {
189
+ threads.push_back ({nThread, jni->NewWeakGlobalRef (thread)});
190
+ }
191
+ }
192
+ jni->DeleteLocalRef (thread);
189
193
}
190
- jvmti->Deallocate ((unsigned char *)threads_ptr);
194
+ }
195
+ jvmti->Deallocate ((unsigned char *)threads_ptr);
191
196
};
192
197
193
198
auto sampleThreads = [&](ThreadEntry& thread_entry, int & num_failures, int & threads_already_exited, int & permission_denied) {
194
199
static jint max_stack_depth = (jint)Profiler::instance ()->max_stack_depth ();
195
200
static jvmtiFrameInfo* frame_buffer = new jvmtiFrameInfo[max_stack_depth];
196
201
static jvmtiEnv* jvmti = VM::jvmti ();
202
+ static JNIEnv* jni = VM::jni ();
197
203
198
204
int num_frames = 0 ;
199
- jvmtiError err = jvmti->GetStackTrace (thread_entry.java , 0 , max_stack_depth, frame_buffer, &num_frames);
205
+ if (thread_entry.java_ref == nullptr ) {
206
+ num_failures++;
207
+ return false ;
208
+ }
209
+
210
+ jobject thread = jni->NewLocalRef (thread_entry.java_ref );
211
+ if (thread == nullptr ) {
212
+ num_failures++;
213
+ jni->DeleteWeakGlobalRef (thread_entry.java_ref );
214
+ return false ;
215
+ }
216
+
217
+ jint thread_state;
218
+ jvmtiError state_err = jvmti->GetThreadState (thread, &thread_state);
219
+ if (state_err != JVMTI_ERROR_NONE || (thread_state & JVMTI_THREAD_STATE_TERMINATED) != 0 ) {
220
+ num_failures++;
221
+ jni->DeleteWeakGlobalRef (thread_entry.java_ref );
222
+ jni->DeleteLocalRef (thread);
223
+ return false ;
224
+ }
225
+ jvmtiError err = jvmti->GetStackTrace (thread, 0 , max_stack_depth, frame_buffer, &num_frames);
226
+ // cleanup the reference(s) to the java thread
227
+ jni->DeleteWeakGlobalRef (thread_entry.java_ref );
228
+ jni->DeleteLocalRef (thread);
229
+
200
230
if (err != JVMTI_ERROR_NONE) {
201
231
num_failures++;
202
232
if (err == JVMTI_ERROR_THREAD_NOT_ALIVE) {
203
233
threads_already_exited++;
204
234
}
205
235
return false ;
206
236
}
237
+ if (num_frames == 0 ) {
238
+ // some JVMTI attached threads are Java-like but have no stack; we can just ignore them
239
+ return true ;
240
+ }
207
241
ExecutionEvent event;
208
242
VMThread* vm_thread = thread_entry.native ;
209
243
int raw_thread_state = vm_thread->state ();
@@ -267,6 +301,5 @@ void WallClockASGCT::timerLoop() {
267
301
}
268
302
return true ;
269
303
};
270
-
271
304
timerLoopCommon<int >(collectThreads, sampleThreads, _reservoir_size, _interval);
272
305
}
0 commit comments