TL;DR why don’t spawned threads have the same PID returned by clone3? Test
with this in each of the projects, one with std::threads::spaw and the other
with tokio::spawn.
strace -e trace="fork,clone,clone3,exit,execve" <executable>
Repository: https://codeberg.org/allonsyeet/threads_how_do_they_work
Output for executable using only stdlib
➜ threads_how_do_they_work git:(main) ✗ strace -e trace=fork,clone,clone3,exit,execve stdonly/target/debug/pulling_on_this_thread
execve("stdonly/target/debug/pulling_on_this_thread", ["stdonly/target/debug/pulling_on_"...], 0x7ffdf11baad0 /* 108 vars */) = 0
clone3({flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTI
D, child_tid=0x7fc6d0d70990, parent_tid=0x7fc6d0d70990, exit_signal=0, stack=0x7fc6d0b70000, stack_size=0x1fff00, tls=0x7fc6d0d706c0} =>
{parent_tid=[8628]}, 88) = 8628
8625 => 8627
clone3({flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTI
D, child_tid=0x7fc6d0b6f990, parent_tid=0x7fc6d0b6f990, exit_signal=0, stack=0x7fc6d096f000, stack_size=0x1fff00, tls=0x7fc6d0b6f6c0} =>
{parent_tid=[8629]}, 88) = 8629
8625 => 8627
clone3({flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTI
D, child_tid=0x7fc6d096e990, parent_tid=0x7fc6d096e990, exit_signal=0, stack=0x7fc6d076e000, stack_size=0x1fff00, tls=0x7fc6d096e6c0} =>
{parent_tid=[8630]}, 88) = 8630
8625 => 8627
clone3({flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTI
D, child_tid=0x7fc6d076d990, parent_tid=0x7fc6d076d990, exit_signal=0, stack=0x7fc6d056d000, stack_size=0x1fff00, tls=0x7fc6d076d6c0} =>
{parent_tid=[8631]}, 88) = 8631
8625 => 8627
+++ exited with 0 +++
Output for tokio:
➜ threads_how_do_they_work git:(main) ✗ strace -e trace=fork,clone,clone3,exit,execve ./tokio_drifting/target/debug/tokio_drifting mult
i
execve("./tokio_drifting/target/debug/tokio_drifting", ["./tokio_drifting/target/debug/to"..., "multi"], 0x7ffc055bf958 /* 108 vars */) =
0
clone3({flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTI
D, child_tid=0x7f58d055c990, parent_tid=0x7f58d055c990, exit_signal=0, stack=0x7f58d035c000, stack_size=0x1ffe40, tls=0x7f58d055c6c0} =>
{parent_tid=[8687]}, 88) = 8687
clone3({flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTI
D, child_tid=0x7f58d035b990, parent_tid=0x7f58d035b990, exit_signal=0, stack=0x7f58d015b000, stack_size=0x1ffe40, tls=0x7f58d035b6c0} =>
{parent_tid=[8688]}, 88) = 8688
clone3({flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTI
D, child_tid=0x7f58cbfff990, parent_tid=0x7f58cbfff990, exit_signal=0, stack=0x7f58cbdff000, stack_size=0x1ffe40, tls=0x7f58cbfff6c0} =>
{parent_tid=[8689]}, 88) = 8689
clone3({flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTI
D, child_tid=0x7f58cbdfe990, parent_tid=0x7f58cbdfe990, exit_signal=0, stack=0x7f58cbbfe000, stack_size=0x1ffe40, tls=0x7f58cbdfe6c0} =>
{parent_tid=[8690]}, 88) = 8690
8686, 8684
8686, 8684
8686, 8684
8686, 8684
+++ exited with 0 +++
Why isn’t the output of getpid the same as the output of clone3?
UPDATE: After reading the man page, getpid will give the thread group ID, not
the process ID of the current thread. For that, use gettid.
stdonly:
➜ threads_how_do_they_work git:(main) ✗ strace -e trace=fork,clone,clone3,exit,execve ./stdonly/target/debug/pulling_on_this_threadexecve("./stdonly/target/debug/pulling_on_this_thread", ["./stdonly/target/debug/pulling_o"...], 0x7fff5a3dd160 /* 105 vars */) = 0
Root pid: 10837
clone3({flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, child_tid=0x7f62699e8990, parent_tid=0x7f62699e8990, exit_signal=0, stack=0x7f62697e8000, stack_size=0x1fff00, tls=0x7f62699e86c0} =>{parent_tid=[10840]}, 88) = 10840
(gettid, getpid, getppid) = (10840, 10839, 10837)
clone3({flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, child_tid=0x7f62697e7990, parent_tid=0x7f62697e7990, exit_signal=0, stack=0x7f62695e7000, stack_size=0x1fff00, tls=0x7f62697e76c0} =>{parent_tid=[10841]}, 88) = 10841
(gettid, getpid, getppid) = (10841, 10839, 10837)
clone3({flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, child_tid=0x7f62695e6990, parent_tid=0x7f62695e6990, exit_signal=0, stack=0x7f62693e6000, stack_size=0x1fff00, tls=0x7f62695e66c0} =>{parent_tid=[10842]}, 88) = 10842
(gettid, getpid, getppid) = (10842, 10839, 10837)
clone3({flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, child_tid=0x7f62693e5990, parent_tid=0x7f62693e5990, exit_signal=0, stack=0x7f62691e5000, stack_size=0x1fff00, tls=0x7f62693e56c0} =>{parent_tid=[10843]}, 88) = 10843
(gettid, getpid, getppid) = (10843, 10839, 10837)
+++ exited with 0 +++
tokio:
➜ threads_how_do_they_work git:(main) ✗ strace -e trace=fork,clone,clone3,exit,execve ./tokio_drifting/target/debug/tokio_drifting multi
execve("./tokio_drifting/target/debug/tokio_drifting", ["./tokio_drifting/target/debug/to"..., "multi"], 0x7ffd82a298d8 /* 105 vars */) = 0
clone3({flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, child_tid=0x7f7f461a7990, parent_tid=0x7f7f461a7990, exit_signal=0, stack=0x7f7f45fa7000, stack_size=0x1ffe40, tls=0x7f7f461a76c0} =>{parent_tid=[13274]}, 88) = 13274
clone3({flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, child_tid=0x7f7f45fa6990, parent_tid=0x7f7f45fa6990, exit_signal=0, stack=0x7f7f45da6000, stack_size=0x1ffe40, tls=0x7f7f45fa66c0} =>{parent_tid=[13275]}, 88) = 13275
clone3({flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, child_tid=0x7f7f45da5990, parent_tid=0x7f7f45da5990, exit_signal=0, stack=0x7f7f45ba5000, stack_size=0x1ffe40, tls=0x7f7f45da56c0} =>{parent_tid=[13276]}, 88) = 13276
clone3({flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, child_tid=0x7f7f45ba4990, parent_tid=0x7f7f45ba4990, exit_signal=0, stack=0x7f7f459a4000, stack_size=0x1ffe40, tls=0x7f7f45ba46c0} =>{parent_tid=[13277]}, 88) = 13277
Root PID = 13273
(gettid, getpid, getppid) = (13277, 13273, 13271)
(gettid, getpid, getppid) = (13276, 13273, 13271)
(gettid, getpid, getppid) = (13275, 13273, 13271)
(gettid, getpid, getppid) = (13274, 13273, 13271)
+++ exited with 0 +++
Mystery solved I suppose, if CLONE_THREAD is set, these things get weird:
getpidwill return the thread group IDgettidwill return the thread ID within the thread groupgetppidwill return the thread leader ID.
If you want to understand more, check out the manual pages for
clone3, and
specifically CLONE_THREAD section,
getpid and
gettid
