It’s been a long time since my promise to publish a detailed write-up on what the hell was actually going on inside qemu.

Qt, for its Unix QProcess implementation, utilises forkfd library, (See also: https://github.com/qt/qtbase/tree/dev/src/3rdparty/forkfd) as a helper library to fork subprocess.

pidfd is a new kernel feature, which has just been added to the kernel upon v5.2.

Since this merge, Qt added a new configuration feature (forkfd_pidfd, “CLONE_PIDFD support in forkfd”) and it was default to ON on Linux.

When this feature is ON, Qt does nothing special, forkfd library selectively uses either forkfd() or fork() based on kernel version: (it goes into this branch and then sets CLONE_PIDFD here before calling clone)

OTOH, if the feature is OFF, Qt sets the FFD_USE_FORK flag (say: forkfd please use fork anyway) when calling ::forkfd(), which will cause forkfd to use fork() direcly.

Under regular circumstances, this works well, forkfd is smart enough to correctly detect the kernel version and use the correct syscall, however, things go south fast when qemu-user steps in:

  1. Qt has no FFD_USE_FORK set, and
  2. forkfd thinks the kernel has correct forkfd syscall implementation (because it should have), and
  3. QEMU has no support for clone-ing with CLONE_PIDFD yet (there’s a possibly abandoned patch)

(original blog post: 记一次-debug-qmake)