Gleb Popov
2018-08-24 14:53:28 UTC
I'm debugging a Qt test app that hangs when launching a QProcess.
The parent does the following:
QProcess p;
...
p.start();
p.waitForStarted(-1); // wait indefinitely
Under the hood starting the QProcess involves creating a pair of pipes and
forking:
qt_create_pipe(childStartedPipe);
...
pid_t childPid;
::forkfd(FFD_CLOEXEC, &childPid);
and waiting for it to be started is just ppoll()'ing on the pipe
pollfd pfd = qt_make_pollfd(childStartedPipe[0], POLLIN);
if (qt_poll_msecs(&pfd, 1, msecs) == 0) {
...
On the child side the code looks like
::signal(SIGPIPE, SIG_DFL);
...
qt_safe_close(childStartedPipe[0]);
...
qt_safe_execv(argv[0], argv);
So, the problem is that after forking the parent process hangs on polling
and child process hangs inside signal call; Here is the backtrace:
#0 _umtx_op_err () at
/usr/src/lib/libthr/arch/amd64/amd64/_umtx_op_err.S:37
#1 0x0000000802bd9571 in __thr_rwlock_rdlock (rwlock=0x802bf3200,
flags=<optimized out>, tsp=<optimized out>) at
/usr/src/lib/libthr/thread/thr_umtx.c:307
#2 0x0000000802be24c0 in _thr_rwlock_rdlock (flags=0, tsp=0x0,
rwlock=<optimized out>) at /usr/src/lib/libthr/thread/thr_umtx.h:232
#3 _thr_rtld_rlock_acquire (lock=0x802bf3200) at
/usr/src/lib/libthr/thread/thr_rtld.c:125
#4 0x000000080024e63b in rlock_acquire (lock=0x80025f0a0 <rtld_locks>,
lockstate=0x7fffffffc678) at /usr/src/libexec/rtld-elf/rtld_lock.c:208
#5 0x00000008002472dd in _rtld_bind (obj=0x80027b000, reloff=4416) at
/usr/src/libexec/rtld-elf/rtld.c:788
#6 0x000000080024404d in _rtld_bind_start () at
/usr/src/libexec/rtld-elf/amd64/rtld_start.S:121
#7 0x0000000803d31a76 in QProcessPrivate::execChild (this=0x81a9716c0,
workingDir=0x0, argv=0x81fde5760, envp=0x0) at io/qprocess_unix.cpp:537
Any idea what causes signal() to not return? I haven't extracted a minimal
repro yet, wanted to ask for any clues first.
The code in question is here:
https://github.com/qt/qtbase/blob/5.11/src/corelib/io/qprocess_unix.cpp
Relevant functions are QProcessPrivate::startProcess(),
QProcessPrivate::execChild(), QProcessPrivate::waitForStarted().
Thanks in advance.
The parent does the following:
QProcess p;
...
p.start();
p.waitForStarted(-1); // wait indefinitely
Under the hood starting the QProcess involves creating a pair of pipes and
forking:
qt_create_pipe(childStartedPipe);
...
pid_t childPid;
::forkfd(FFD_CLOEXEC, &childPid);
and waiting for it to be started is just ppoll()'ing on the pipe
pollfd pfd = qt_make_pollfd(childStartedPipe[0], POLLIN);
if (qt_poll_msecs(&pfd, 1, msecs) == 0) {
...
On the child side the code looks like
::signal(SIGPIPE, SIG_DFL);
...
qt_safe_close(childStartedPipe[0]);
...
qt_safe_execv(argv[0], argv);
So, the problem is that after forking the parent process hangs on polling
and child process hangs inside signal call; Here is the backtrace:
#0 _umtx_op_err () at
/usr/src/lib/libthr/arch/amd64/amd64/_umtx_op_err.S:37
#1 0x0000000802bd9571 in __thr_rwlock_rdlock (rwlock=0x802bf3200,
flags=<optimized out>, tsp=<optimized out>) at
/usr/src/lib/libthr/thread/thr_umtx.c:307
#2 0x0000000802be24c0 in _thr_rwlock_rdlock (flags=0, tsp=0x0,
rwlock=<optimized out>) at /usr/src/lib/libthr/thread/thr_umtx.h:232
#3 _thr_rtld_rlock_acquire (lock=0x802bf3200) at
/usr/src/lib/libthr/thread/thr_rtld.c:125
#4 0x000000080024e63b in rlock_acquire (lock=0x80025f0a0 <rtld_locks>,
lockstate=0x7fffffffc678) at /usr/src/libexec/rtld-elf/rtld_lock.c:208
#5 0x00000008002472dd in _rtld_bind (obj=0x80027b000, reloff=4416) at
/usr/src/libexec/rtld-elf/rtld.c:788
#6 0x000000080024404d in _rtld_bind_start () at
/usr/src/libexec/rtld-elf/amd64/rtld_start.S:121
#7 0x0000000803d31a76 in QProcessPrivate::execChild (this=0x81a9716c0,
workingDir=0x0, argv=0x81fde5760, envp=0x0) at io/qprocess_unix.cpp:537
Any idea what causes signal() to not return? I haven't extracted a minimal
repro yet, wanted to ask for any clues first.
The code in question is here:
https://github.com/qt/qtbase/blob/5.11/src/corelib/io/qprocess_unix.cpp
Relevant functions are QProcessPrivate::startProcess(),
QProcessPrivate::execChild(), QProcessPrivate::waitForStarted().
Thanks in advance.