[Development] Deprecating the static QProcess::startDetached() overloads

Thiago Macieira thiago.macieira at intel.com
Wed Feb 27 22:47:46 CET 2019


On Wednesday, 27 February 2019 12:22:05 PST Thiago Macieira wrote:
> Good point: so long as the parent process is still running, it MUST
> waitpid() on the child processes. So even if we make QProcess front-end
> abandon the child, the backend in forkfd must still know about it.
> 
> When the parent process exits, the children will be reparented to PID 1. But
> their controlling TTYs, process groups and session IDs will not change. We
> can assume you properly redirected std{in,out,err} away from the TTYs if
> you meant to detach, but we need to know whether to detach the controlling
> TTY too (if any), otherwise the process will get a SIGHUP when the TTY
> itself gets closed. As for PGRP and SID, I don't remember those Unix arcana
> details to predict what would happen.

I've just realised that my alternative implementation of forkfd that 
implements the double-forking for all processes could be handy here. For every 
child that you start, it starts an intermediary babysitter process whose only 
job is to waitpid() on the child. I implemented this because this babysitter 
process is not running alongside third party library code that could interfere 
with the SIGCHLD signal handler.

However, it has serious drawbacks, so I don't think we should use it:

1) it creates one extra process per child, which lowers the number of 
concurrent children you can have by half;

2) it's Linux-only, since I can't use fork() due to deadlocks. It uses 
syscall(SYS_clone, ...) directly. And since it can't allocate memory due to 
the same deadlocks, it needs to use syscall(SYS_getdents64) to list open files 
in /proc/self/fd.

3) the babysitter process does not know when the parent exits, so it will keep 
running and keep the entire set of libraries of the Qt parent application 
loaded in memory for as long as the child process is running.

3.bis) as a result of (3), it will cause COW in any memory written to by the 
parent process.

I implemented this because, unlike the current solution, if you pass the 
forkfd pipe to another process and exit, the receiving process will still be 
able to get the exit notification, as the kernel implementation intended to 
do. 

(3) can be mitigated polling on the outgoing pipe, which allows us to find out 
if all the reading ends have closed, then exit the babysitter process. That 
won't solve (3.bis) nor will it solve the case where the parent execve()s a 
smaller executable. To do that, we'd need to go deeper into Linux-only and 
unmap any other memory regions we didn't need, and switch to an alternate 
stack.

To remove the Linux-only dependency, the only solution I can think of is to 
use a libexec executable, but that has a startup cost of its own. And nothing 
solves (1).

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Software Architect - Intel System Software Products






More information about the Development mailing list