summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorRoland McGrath <roland@redhat.com>2004-10-18 08:53:22 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-10-18 08:53:22 -0700
commit04bff08854d97652f0c31b0b1a577a7e9704c895 (patch)
tree548c129829bf5a42e7afcb37681d9d98409c1f14 /kernel
parent31180071ee5e6cc6ff4d036d655c556f582f74e4 (diff)
[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: Roland McGrath <roland@redhat.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/exit.c79
1 files changed, 58 insertions, 21 deletions
diff --git a/kernel/exit.c b/kernel/exit.c
index e018bf6169d2..426d3ae722ba 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -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;
}
}
@@ -1412,7 +1448,8 @@ asmlinkage long sys_wait4(pid_t pid, int __user *stat_addr,
{
long ret;
- if (options & ~(WNOHANG|WUNTRACED|__WNOTHREAD|__WCLONE|__WALL))
+ if (options & ~(WNOHANG|WUNTRACED|WCONTINUED|
+ __WNOTHREAD|__WCLONE|__WALL))
return -EINVAL;
ret = do_wait(pid, options | WEXITED, NULL, stat_addr, ru);