◐ Shell
clean mode source ↗

gh-135953: Properly obtain main thread identifier in Gecko Collector by flowln · Pull Request #146045 · python/cpython

Since running a profiler via CLI (python -m profiling.sampling run)
spawns a new subprocess where the actual user-specified code will run,
a call to threading.main_thread() in the collector's process will not
return the profiled process's main thread.

To combat this, we rely on the fact that thread objects are inserted
in such a way that the first object in the list represents the oldest
ThreadState object [1], which corresponds to a ThreadState associated
with the main thread.

[1] - https://github.com/python/cpython/blob/1b118353bb0a9d816de6ef673f3b11775de5bec5/Include/internal/pycore_interp_structs.h#L831

Signed-off-by: Sofia Donato Ferreira <flowlnlnln@gmail.com>
The ordering is actually newest -> oldest, since the _remote_debugging
code traverses the ThreadState linked list in the intepreter state, appending
to a list of threads in-order.

Signed-off-by: Sofia Donato Ferreira <flowlnlnln@gmail.com>
It seems to sometimes happen that some samples (possibly at the very start / end)
do not have any active threads in the interpreter state.

It is OK to make main_tid maybe None here, since if it is, the threads list is
empty, and so the for loop will not execute anyways.

Signed-off-by: Sofia Donato Ferreira <flowlnlnln@gmail.com>
…tate

Signed-off-by: Sofia Donato Ferreira <flowlnlnln@gmail.com>
… in Gecko test

Signed-off-by: Sofia Donato Ferreira <flowlnlnln@gmail.com>

pablogsal

…terInfo field

Replace the main_thread_id field in InterpreterInfo with a
THREAD_STATUS_MAIN_THREAD status flag set directly in the thread
unwinding code. This simplifies the struct from 3 to 2 fields and
removes the need to compare thread IDs at the Python level.

pablogsal

@pablogsal

CuriousLearner added a commit to CuriousLearner/cpython that referenced this pull request

Mar 23, 2026

ljfp pushed a commit to ljfp/cpython that referenced this pull request

Apr 25, 2026