lkml.org 
[lkml]   [2011]   [Mar]   [8]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 8/8] job control: Don't send duplicate job control stop notification while ptraced
    Date
    Just as group_exit_code shouldn't be generated when a PTRACE_CONT'd
    task re-enters job control stop, notifiction for the event should be
    suppressed too. The logic is the same as the group_exit_code
    generation suppression in do_signal_stop(), if SIGNAL_STOP_STOPPED is
    already set, the task is re-entering job control stop without
    intervening SIGCONT and the notifications should be suppressed.

    Test case follows.

    #include <stdio.h>
    #include <unistd.h>
    #include <signal.h>
    #include <time.h>
    #include <sys/ptrace.h>
    #include <sys/wait.h>

    static const struct timespec ts100ms = { .tv_nsec = 100000000 };
    static pid_t tracee, tracer;
    static const char *pid_who(pid_t pid)
    {
    return pid == tracee ? "tracee" : (pid == tracer ? "tracer" : "mommy ");
    }
    static void sigchld_sigaction(int signo, siginfo_t *si, void *ucxt)
    {
    printf("%s: SIG status=%02d code=%02d (%s)\n",
    pid_who(getpid()), si->si_status, si->si_code,
    pid_who(si->si_pid));
    }
    int main(void)
    {
    const struct sigaction chld_sa = { .sa_sigaction = sigchld_sigaction,
    .sa_flags = SA_SIGINFO|SA_RESTART };
    siginfo_t si;
    sigaction(SIGCHLD, &chld_sa, NULL);

    tracee = fork();
    if (!tracee) {
    tracee = getpid();
    while (1)
    pause();
    }
    kill(tracee, SIGSTOP);
    waitid(P_PID, tracee, &si, WSTOPPED);

    tracer = fork();
    if (!tracer) {
    tracer = getpid();
    ptrace(PTRACE_ATTACH, tracee, NULL, NULL);
    waitid(P_PID, tracee, &si, WSTOPPED);
    ptrace(PTRACE_CONT, tracee, NULL, (void *)(long)si.si_status);
    waitid(P_PID, tracee, &si, WSTOPPED);
    ptrace(PTRACE_CONT, tracee, NULL, (void *)(long)si.si_status);
    waitid(P_PID, tracee, &si, WSTOPPED);
    printf("tracer: detaching\n");
    ptrace(PTRACE_DETACH, tracee, NULL, NULL);
    return 0;
    }
    while (1)
    pause();
    return 0;
    }
    Before the patch, the parent gets the second notification for the
    tracee after the tracer detaches. si_status is zero because
    group_exit_code is not set by the group stop completion which
    triggered this notification.

    mommy : SIG status=19 code=05 (tracee)
    tracer: SIG status=00 code=05 (tracee)
    tracer: SIG status=19 code=04 (tracee)
    tracer: SIG status=00 code=05 (tracee)
    tracer: detaching
    mommy : SIG status=00 code=05 (tracee)
    mommy : SIG status=00 code=01 (tracer)
    ^C

    After the patch, the duplicate notification is gone.

    mommy : SIG status=19 code=05 (tracee)
    tracer: SIG status=00 code=05 (tracee)
    tracer: SIG status=19 code=04 (tracee)
    tracer: SIG status=00 code=05 (tracee)
    tracer: detaching
    mommy : SIG status=00 code=01 (tracer)
    ^C

    Signed-off-by: Tejun Heo <tj@kernel.org>
    ---
    kernel/signal.c | 10 +++++++++-
    1 files changed, 9 insertions(+), 1 deletions(-)
    diff --git a/kernel/signal.c b/kernel/signal.c
    index 74f097c..8304563 100644
    --- a/kernel/signal.c
    +++ b/kernel/signal.c
    @@ -268,6 +268,10 @@ void task_clear_group_stop_pending(struct task_struct *task)
    *
    * CONTEXT:
    * Must be called with @task->sighand->siglock held.
    + *
    + * RETURNS:
    + * %true if group stop completion should be notified to the parent, %false
    + * otherwise.
    */
    static bool task_participate_group_stop(struct task_struct *task)
    {
    @@ -284,7 +288,11 @@ static bool task_participate_group_stop(struct task_struct *task)
    if (!WARN_ON_ONCE(sig->group_stop_count == 0))
    sig->group_stop_count--;

    - if (!sig->group_stop_count) {
    + /*
    + * Tell the caller to notify completion iff we are entering into a
    + * fresh group stop. Read comment in do_signal_stop() for details.
    + */
    + if (!sig->group_stop_count && !(sig->flags & SIGNAL_STOP_STOPPED)) {
    sig->flags = SIGNAL_STOP_STOPPED;
    return true;
    }
    --
    1.7.1


    \
     
     \ /
      Last update: 2011-03-08 20:59    [W:1.699 / U:0.416 seconds]
    ©2003-2014 Jasper Spaans. hosted at Digital Ocean