From: Roland McGrath POSIX specifies the new WCONTINUED flag for waitpid, not just for waitid. I overlooked this addition when I implemented waitid. The real work was already done to support waitid, but waitpid needs to report the results Signed-off-by: Roland McGrath Signed-off-by: Andrew Morton --- 25-akpm/kernel/exit.c | 79 ++++++++++++++++++++++++++++++++++++-------------- 1 files changed, 58 insertions(+), 21 deletions(-) diff -puN kernel/exit.c~add-wcontinued-support-to-wait4-syscall kernel/exit.c --- 25/kernel/exit.c~add-wcontinued-support-to-wait4-syscall Thu Sep 30 15:29:31 2004 +++ 25-akpm/kernel/exit.c Thu Sep 30 15:29:31 2004 @@ -1228,6 +1228,58 @@ bail_ref: return retval; } +/* + * Handle do_wait work for one task in a live, non-stopped state. + * read_lock(&tasklist_lock) on entry. If we return zero, we still hold + * the lock and this task is uninteresting. If we return nonzero, we have + * released the lock and the system call should return. + */ +static int wait_task_continued(task_t *p, int noreap, + struct siginfo __user *infop, + int __user *stat_addr, struct rusage __user *ru) +{ + int retval; + pid_t pid; + uid_t uid; + + if (unlikely(!p->signal)) + return 0; + + if (p->signal->stop_state >= 0) + return 0; + + spin_lock_irq(&p->sighand->siglock); + if (p->signal->stop_state >= 0) { /* Re-check with the lock held. */ + spin_unlock_irq(&p->sighand->siglock); + return 0; + } + if (!noreap) + p->signal->stop_state = 0; + spin_unlock_irq(&p->sighand->siglock); + + pid = p->pid; + uid = p->uid; + get_task_struct(p); + read_unlock(&tasklist_lock); + + if (!infop) { + retval = ru ? getrusage(p, RUSAGE_BOTH, ru) : 0; + put_task_struct(p); + if (!retval && stat_addr) + retval = put_user(0xffff, stat_addr); + if (!retval) + retval = p->pid; + } else { + retval = wait_noreap_copyout(p, pid, uid, + CLD_CONTINUED, SIGCONT, + infop, ru); + BUG_ON(retval == 0); + } + + return retval; +} + + static long do_wait(pid_t pid, int options, struct siginfo __user *infop, int __user *stat_addr, struct rusage __user *ru) { @@ -1290,27 +1342,11 @@ repeat: check_continued: if (!unlikely(options & WCONTINUED)) continue; - if (unlikely(!p->signal)) - continue; - spin_lock_irq(&p->sighand->siglock); - if (p->signal->stop_state < 0) { - pid_t pid; - uid_t uid; - - if (!(options & WNOWAIT)) - p->signal->stop_state = 0; - spin_unlock_irq(&p->sighand->siglock); - pid = p->pid; - uid = p->uid; - get_task_struct(p); - read_unlock(&tasklist_lock); - retval = wait_noreap_copyout(p, pid, - uid, CLD_CONTINUED, - SIGCONT, infop, ru); - BUG_ON(retval == 0); + retval = wait_task_continued( + p, (options & WNOWAIT), + infop, stat_addr, ru); + if (retval != 0) /* He released the lock. */ goto end; - } - spin_unlock_irq(&p->sighand->siglock); break; } } @@ -1404,7 +1440,8 @@ asmlinkage long sys_waitid(int which, pi asmlinkage long sys_wait4(pid_t pid, int __user *stat_addr, int options, struct rusage __user *ru) { - if (options & ~(WNOHANG|WUNTRACED|__WNOTHREAD|__WCLONE|__WALL)) + if (options & ~(WNOHANG|WUNTRACED|WCONTINUED| + __WNOTHREAD|__WCLONE|__WALL)) return -EINVAL; return do_wait(pid, options | WEXITED, NULL, stat_addr, ru); } _