Re: [patch] Fix Linux attach to signalled/stopped processes

Daniel Jacobowitz
2008-04-14T14:35:17Z

On Fri, Apr 11, 2008 at 05:01:55PM -0700, Roland McGrath wrote:
> Ah, right. You can also do:
>
> PTRACE_ATTACH -> pending SIGSTOP
> ... if running -> stopped, no pending SIGSTOP
> ... if stopped -> still stopped, pending SIGSTOP
> tkill (SIGSTOP, tid) -> pending SIGSTOP
>
> PTRACE_CONT, tid, 0 -> if not stopped the first time yet, ESRCH
> -> if stopped, wakes up, dequeues SIGSTOP
> wait -> always see it stop
>
> You just don't know whether you'll see one more spurious SIGSTOP or not.
> (Once you've waited, you can synchronously check /proc, but that doesn't
> tell you whether it was your spurious one or just an outside one sent
> right now.)

Isn't this still racy? SIGCONT wakeups happen synchronously, but
SIGSTOP stops do not. After the PTRACE_ATTACH the thread might be
running with a pending SIGSTOP. Then the tkill has no effect, and
if the thread stops between the tkill and the PTRACE_CONT it will have
no reason to stop again.

Fixing the race is not hard though: grub around in /proc for status.
First PTRACE_ATTACH, which sends a SIGSTOP. Then check /proc. If it
is running, it must have a pending SIGSTOP; we can wait for it so skip
the tkill and the PTRACE_CONT. If it is not running, it may or may
not have a pending SIGSTOP. So do as you described above with tkill
and PTRACE_CONT.

This has the same problem of using SIGSTOP in that it may stop other
threads of the process. But it avoids using SIGCONT, so it will not
wake up other threads of the process. For GDB's purposes, that is
currently good enough - strictly better than before, while the
SIGCONT approach could cause other threads to run before we attached
to them.

Thanks again for the assistance. This conversation gave me a useful
insight into one of those things you already probably know: GDB's use
of SIGSTOP instead of another signal is not significant. We want the
process to be signalled, that's all. Since each SIGSTOP we send stops
the whole group, I suspect if I checked using PTRACE_GETSIGINFO I
would find most of the threads in finish_stop and not fully ptrace
controllable. To preserve our last vestiges of LinuxThreads support
we have to continue sending SIGSTOP once per thread, or else use a
different signal.

I'm not going to make that change right now, but I will add some
comments about it. We could probably use an RT signal at each point
we want a stop.

--
Daniel Jacobowitz
CodeSourcery