Commit 04bff088 authored by Roland McGrath's avatar Roland McGrath Committed by Linus Torvalds

[PATCH] add WCONTINUED support to wait4 syscall

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: default avatarRoland McGrath <roland@redhat.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 31180071
...@@ -1228,6 +1228,58 @@ static int wait_task_stopped(task_t *p, int delayed_group_leader, int noreap, ...@@ -1228,6 +1228,58 @@ static int wait_task_stopped(task_t *p, int delayed_group_leader, int noreap,
return retval; 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, static long do_wait(pid_t pid, int options, struct siginfo __user *infop,
int __user *stat_addr, struct rusage __user *ru) int __user *stat_addr, struct rusage __user *ru)
{ {
...@@ -1290,27 +1342,11 @@ static long do_wait(pid_t pid, int options, struct siginfo __user *infop, ...@@ -1290,27 +1342,11 @@ static long do_wait(pid_t pid, int options, struct siginfo __user *infop,
check_continued: check_continued:
if (!unlikely(options & WCONTINUED)) if (!unlikely(options & WCONTINUED))
continue; continue;
if (unlikely(!p->signal)) retval = wait_task_continued(
continue; p, (options & WNOWAIT),
spin_lock_irq(&p->sighand->siglock); infop, stat_addr, ru);
if (p->signal->stop_state < 0) { if (retval != 0) /* He released the lock. */
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);
goto end; goto end;
}
spin_unlock_irq(&p->sighand->siglock);
break; break;
} }
} }
...@@ -1412,7 +1448,8 @@ asmlinkage long sys_wait4(pid_t pid, int __user *stat_addr, ...@@ -1412,7 +1448,8 @@ asmlinkage long sys_wait4(pid_t pid, int __user *stat_addr,
{ {
long ret; long ret;
if (options & ~(WNOHANG|WUNTRACED|__WNOTHREAD|__WCLONE|__WALL)) if (options & ~(WNOHANG|WUNTRACED|WCONTINUED|
__WNOTHREAD|__WCLONE|__WALL))
return -EINVAL; return -EINVAL;
ret = do_wait(pid, options | WEXITED, NULL, stat_addr, ru); ret = do_wait(pid, options | WEXITED, NULL, stat_addr, ru);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment