Skip to content

Commit 27434c6

Browse files
authored
gh-138122: Skip threads on EPERM in blocking mode profiler (GH-143368)
When using blocking mode in the remote debugging profiler, ptrace calls to seize threads can fail with EPERM if the thread has exited between listing and attaching, is in a special kernel state, or is already being traced. Previously this raised a RuntimeError that was caught by the Python sampling loop,and retried indefinitely since EPERM is a persistent condition that will not resolve on its own. Treat EPERM the same as ESRCH by returning 1 (skip this thread) instead of -1 (fatal error). This allows profiling to continue with the threads that can be traced rather than entering an endless retry loop printing the same error message repeatedly.
1 parent 2c39b9d commit 27434c6

File tree

2 files changed

+11
-2
lines changed

2 files changed

+11
-2
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix endless retry loop in :mod:`profiling.sampling` blocking mode when
2+
threads cannot be seized due to ``EPERM``. Such threads are now skipped
3+
instead of causing repeated error messages. Patch by Pablo Galindo.

Modules/_remote_debugging/threads.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -632,15 +632,21 @@ seize_thread(pid_t tid)
632632
if (errno == ESRCH) {
633633
return 1; // Thread gone, skip
634634
}
635+
if (errno == EPERM) {
636+
// Thread may have exited, be in a special state, or already be traced.
637+
// Skip rather than fail - this avoids endless retry loops when
638+
// threads transiently become inaccessible.
639+
return 1;
640+
}
635641
if (errno == EINVAL || errno == EIO) {
636642
// Fallback for older kernels
637643
if (ptrace(PTRACE_ATTACH, tid, NULL, NULL) == 0) {
638644
int status;
639645
waitpid(tid, &status, __WALL);
640646
return 0;
641647
}
642-
if (errno == ESRCH) {
643-
return 1; // Thread gone
648+
if (errno == ESRCH || errno == EPERM) {
649+
return 1; // Thread gone or inaccessible
644650
}
645651
}
646652
return -1; // Real error

0 commit comments

Comments
 (0)