Traditionally processes have reaped dead children by waiting on them, the problem with this is it's a synchronous operation that blocks a thread per child.
The only historical non-blocking solution was to listen for signals. Signals are great and all, except that the kernel will sometimes (unavoidably) merge multiple signals together, preventing you from getting a list of dead children. This is problematic if you want to know exactly which children died.
Linux 5.3 introduced a third system to listen for dead children, pidfd. It's a file descriptor which you can pass to epoll to know when a specific child dies. This is great, but it didn't yet support O_NONBLOCK, which meant that to use it in asynchronous (rust) code we need to create an extra thread which just sits around listening for it.
Linux 5.10 brings the ability to make this fd non blocking, so we can integrate this seamlessly into async event loops. Here's some code of mine that does that: https://github.com/gmorenz/async-transpiled-xv6-shell/blob/m...
Thanks to Christian Brauner, Josh Triplett, and Oleg Nesterov: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/lin...