* [PATCH] waitid system call
@ 2004-08-15 23:03 Roland McGrath
2004-08-16 5:40 ` Roland McGrath
0 siblings, 1 reply; 22+ messages in thread
From: Roland McGrath @ 2004-08-15 23:03 UTC (permalink / raw)
To: Linus Torvalds, Andrew Morton; +Cc: Ulrich Drepper, Linux Kernel Mailing List
This patch adds a new system call `waitid'. This is a new POSIX call that
subsumes the rest of the wait* family and can do some things the older
calls cannot. A minor addition is the ability to select what kinds of
status to check for with a mask of independent bits, so you can wait for
just stops and not terminations, for example. A more significant
improvement is the WNOWAIT flag, which allows for polling child status
without reaping. This interface fills in a siginfo_t with the same details
that a SIGCHLD for the status change has; some of that info (e.g. si_uid)
is not available via wait4 or other calls.
I've added a new system call that has the parameter conventions of the
POSIX function because that seems like the cleanest thing. This patch
includes the actual system call table additions for i386 and x86-64; other
architectures will need to assign the system call number, and 64-bit ones
may need to implement 32-bit compat support for it as I did for x86-64.
The new features could instead be provided by some new kludge inventions in
the wait4 system call interface (that's what BSD did). If kludges are
preferable to adding a system call, I can work up something different.
I added a struct rusage field si_rusage to siginfo_t in the SIGCHLD case
(this does not affect the size or layout of the struct). This is not part
of the POSIX interface, but it makes it so that `waitid' subsumes all the
functionality of `wait4'. Future kernel ABIs (new arch's or whatnot) can
have only the `waitid' system call and the rest of the wait* family
including wait3 and wait4 can be implemented in user space using waitid.
There is nothing in user space as yet that would make use of the new field.
Most of the new functionality is implemented purely in the waitid system
call itself. POSIX also provides for the WCONTINUED flag to report when a
child process had been stopped by job control and then resumed with
SIGCONT. Corresponding to this, a SIGCHLD is now generated when a child
resumes (unless SA_NOCLDSTOP is set), with the value CLD_CONTINUED in
siginfo_t.si_code. To implement this, some additional bookkeeping is
required in the signal code handling job control stops.
The motivation for this work is to make it possible to implement the POSIX
semantics of the `waitid' function in glibc completely and correctly. If
changing either the system call interface used to accomplish that, or any
details of the kernel implementation work, would improve the chances of
getting this incorporated, I am more than happy to work through any issues.
Thanks,
Roland
Signed-off-by: Roland McGrath <roland@redhat.com>
--- vanilla-linux-2.6/arch/i386/kernel/entry.S 2004-05-22 22:03:15.000000000 -0700
+++ linux-2.6/arch/i386/kernel/entry.S 2004-07-12 14:03:36.000000000 -0700
@@ -886,5 +886,6 @@ ENTRY(sys_call_table)
.long sys_mq_notify
.long sys_mq_getsetattr
.long sys_ni_syscall /* reserved for kexec */
+ .long sys_waitid
syscall_table_size=(.-sys_call_table)
--- vanilla-linux-2.6/arch/x86_64/ia32/ia32_signal.c 2004-07-13 11:02:33.000000000 -0700
+++ linux-2.6/arch/x86_64/ia32/ia32_signal.c 2004-08-10 18:16:49.000000000 -0700
@@ -74,6 +74,8 @@ int ia32_copy_siginfo_to_user(siginfo_t3
err |= __put_user(from->si_utime, &to->si_utime);
err |= __put_user(from->si_stime, &to->si_stime);
err |= __put_user(from->si_status, &to->si_status);
+ err |= __copy_to_user(&to->si_rusage, &from->si_rusage,
+ sizeof(to->si_rusage));
default:
case __SI_KILL >> 16:
err |= __put_user(from->si_uid, &to->si_uid);
--- vanilla-linux-2.6/arch/x86_64/ia32/sys_ia32.c 2004-07-30 22:49:36.000000000 -0700
+++ linux-2.6/arch/x86_64/ia32/sys_ia32.c 2004-08-11 12:01:41.000000000 -0700
@@ -1151,6 +1151,25 @@ asmlinkage long sys32_clone(unsigned int
parent_tid, child_tid);
}
+asmlinkage long sys32_waitid(int which, compat_pid_t pid,
+ siginfo_t32 __user *uinfo, int options)
+{
+ siginfo_t info;
+ long ret;
+ mm_segment_t old_fs = get_fs();
+
+ info.si_signo = 0;
+ set_fs (KERNEL_DS);
+ ret = sys_waitid(which, pid, (siginfo_t __user *) &info, options);
+ set_fs (old_fs);
+
+ if (ret < 0 || info.si_signo == 0)
+ return ret;
+ BUG_ON(info.si_code & __SI_MASK);
+ info.si_code |= __SI_CHLD;
+ return ia32_copy_siginfo_to_user(uinfo, &info);
+}
+
/*
* Some system calls that need sign extended arguments. This could be done by a generic wrapper.
*/
--- vanilla-linux-2.6/arch/x86_64/ia32/ia32entry.S 2004-05-30 11:55:13.000000000 -0700
+++ linux-2.6/arch/x86_64/ia32/ia32entry.S 2004-08-09 23:56:06.000000000 -0700
@@ -589,6 +589,7 @@ ia32_sys_call_table:
.quad compat_sys_mq_notify
.quad compat_sys_mq_getsetattr
.quad quiet_ni_syscall /* reserved for kexec */
+ .quad sys32_waitid
/* don't forget to change IA32_NR_syscalls */
ia32_syscall_end:
.rept IA32_NR_syscalls-(ia32_syscall_end-ia32_sys_call_table)/8
--- vanilla-linux-2.6/include/asm-generic/siginfo.h 2004-07-13 11:02:33.000000000 -0700
+++ linux-2.6/include/asm-generic/siginfo.h 2004-07-15 14:20:56.000000000 -0700
@@ -3,6 +3,7 @@
#include <linux/compiler.h>
#include <linux/types.h>
+#include <linux/resource.h>
typedef union sigval {
int sival_int;
@@ -74,6 +75,7 @@ typedef struct siginfo {
int _status; /* exit code */
clock_t _utime;
clock_t _stime;
+ struct rusage _rusage;
} _sigchld;
/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
@@ -105,6 +107,7 @@ typedef struct siginfo {
#define si_status _sifields._sigchld._status
#define si_utime _sifields._sigchld._utime
#define si_stime _sifields._sigchld._stime
+#define si_rusage _sifields._sigchld._rusage
#define si_value _sifields._rt._sigval
#define si_int _sifields._rt._sigval.sival_int
#define si_ptr _sifields._rt._sigval.sival_ptr
--- vanilla-linux-2.6/include/asm-i386/unistd.h 2004-08-02 10:14:04.000000000 -0700
+++ linux-2.6/include/asm-i386/unistd.h 2004-08-04 00:18:53.000000000 -0700
@@ -289,8 +289,9 @@
#define __NR_mq_notify (__NR_mq_open+4)
#define __NR_mq_getsetattr (__NR_mq_open+5)
#define __NR_sys_kexec_load 283
+#define __NR_waitid 284
-#define NR_syscalls 284
+#define NR_syscalls 285
/* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */
--- vanilla-linux-2.6/include/asm-x86_64/ia32_unistd.h 2004-05-30 11:55:13.000000000 -0700
+++ linux-2.6/include/asm-x86_64/ia32_unistd.h 2004-07-26 17:59:32.000000000 -0700
@@ -289,6 +289,7 @@
#define __NR_ia32_mq_notify (__NR_ia32_mq_open+4)
#define __NR_ia32_mq_getsetattr (__NR_ia32_mq_open+5)
#define __NR_ia32_kexec 283
+#define __NR_ia32_waitid 284
#define IA32_NR_syscalls 287 /* must be > than biggest syscall! */
--- vanilla-linux-2.6/include/asm-x86_64/ia32.h 2004-05-30 20:07:42.000000000 -0700
+++ linux-2.6/include/asm-x86_64/ia32.h 2004-08-09 21:13:30.000000000 -0700
@@ -121,6 +121,7 @@ typedef struct siginfo32 {
int _status; /* exit code */
compat_clock_t _utime;
compat_clock_t _stime;
+ struct compat_rusage _rusage;
} _sigchld;
/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
--- vanilla-linux-2.6/include/asm-x86_64/unistd.h 2004-06-09 08:17:36.000000000 -0700
+++ linux-2.6/include/asm-x86_64/unistd.h 2004-07-26 15:44:13.000000000 -0700
@@ -554,8 +554,10 @@ __SYSCALL(__NR_mq_notify, sys_mq_notify)
__SYSCALL(__NR_mq_getsetattr, sys_mq_getsetattr)
#define __NR_kexec_load 246
__SYSCALL(__NR_kexec_load, sys_ni_syscall)
+#define __NR_waitid 247
+__SYSCALL(__NR_waitid, sys_waitid)
-#define __NR_syscall_max __NR_kexec_load
+#define __NR_syscall_max __NR_waitid
#ifndef __NO_STUBS
/* user-visible error numbers are in the range -1 - -4095 */
--- vanilla-linux-2.6/include/linux/syscalls.h 2004-06-22 08:27:43.000000000 -0700
+++ linux-2.6/include/linux/syscalls.h 2004-08-09 23:44:22.000000000 -0700
@@ -162,6 +162,8 @@ asmlinkage long sys_exit(int error_code)
asmlinkage void sys_exit_group(int error_code);
asmlinkage long sys_wait4(pid_t pid, unsigned int __user *stat_addr,
int options, struct rusage __user *ru);
+asmlinkage long sys_waitid(int which, pid_t pid,
+ struct siginfo __user *infop, int options);
asmlinkage long sys_waitpid(pid_t pid, unsigned int __user *stat_addr, int options);
asmlinkage long sys_set_tid_address(int __user *tidptr);
asmlinkage long sys_futex(u32 __user *uaddr, int op, int val,
--- vanilla-linux-2.6/include/linux/wait.h 2004-06-24 08:54:26.000000000 -0700
+++ linux-2.6/include/linux/wait.h 2004-07-01 22:56:27.000000000 -0700
@@ -3,11 +3,20 @@
#define WNOHANG 0x00000001
#define WUNTRACED 0x00000002
+#define WSTOPPED WUNTRACED
+#define WEXITED 0x00000004
+#define WCONTINUED 0x00000008
+#define WNOWAIT 0x01000000 /* Don't reap, just poll status. */
#define __WNOTHREAD 0x20000000 /* Don't wait on children of other threads in this group */
#define __WALL 0x40000000 /* Wait on all children, regardless of type */
#define __WCLONE 0x80000000 /* Wait only on non-SIGCHLD children */
+/* First argument to waitid: */
+#define P_ALL 0
+#define P_PID 1
+#define P_PGID 2
+
#ifdef __KERNEL__
#include <linux/config.h>
--- vanilla-linux-2.6/include/linux/sched.h 2004-07-28 23:13:51.000000000 -0700
+++ linux-2.6/include/linux/sched.h 2004-08-05 13:46:40.000000000 -0700
@@ -268,6 +268,8 @@ struct signal_struct {
/* thread group stop support, overloads group_exit_code too */
int group_stop_count;
+ /* 1 if group stopped since last SIGCONT, -1 if SIGCONT since report */
+ int stop_state;
/* POSIX.1b Interval Timers */
struct list_head posix_timers;
--- vanilla-linux-2.6/kernel/exit.c 2004-07-17 21:51:57.000000000 -0700
+++ linux-2.6/kernel/exit.c 2004-08-05 14:42:44.000000000 -0700
@@ -967,16 +967,64 @@ static int eligible_child(pid_t pid, int
return 1;
}
+static int wait_noreap_copyout(task_t *p, pid_t pid, uid_t uid,
+ int why, int status,
+ struct siginfo __user *infop)
+{
+ int retval = getrusage(p, RUSAGE_BOTH, &infop->si_rusage);
+ put_task_struct(p);
+ if (!retval)
+ retval = put_user(SIGCHLD, &infop->si_signo);
+ if (!retval)
+ retval = put_user(0, &infop->si_errno);
+ if (!retval)
+ retval = put_user((short)why, &infop->si_code);
+ if (!retval)
+ retval = put_user(pid, &infop->si_pid);
+ if (!retval)
+ retval = put_user(uid, &infop->si_uid);
+ if (!retval)
+ retval = put_user(status, &infop->si_status);
+ if (!retval)
+ retval = pid;
+ return retval;
+}
+
/*
* Handle sys_wait4 work for one task in state TASK_ZOMBIE. We hold
* 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_zombie(task_t *p, unsigned int __user *stat_addr, struct rusage __user *ru)
+static int wait_task_zombie(task_t *p, int noreap,
+ struct siginfo __user *infop,
+ int __user *stat_addr, struct rusage __user *ru)
{
unsigned long state;
int retval;
+ int status;
+
+ if (unlikely(noreap)) {
+ pid_t pid = p->pid;
+ uid_t uid = p->uid;
+ int exit_code = p->exit_code;
+ int why, status;
+ if (unlikely(p->state != TASK_ZOMBIE))
+ return 0;
+ if (unlikely(p->exit_signal == -1 && p->ptrace == 0))
+ return 0;
+ get_task_struct(p);
+ read_unlock(&tasklist_lock);
+ if ((exit_code & 0x7f) == 0) {
+ why = CLD_EXITED;
+ status = exit_code >> 8;
+ }
+ else {
+ why = (exit_code & 0x80) ? CLD_DUMPED : CLD_KILLED;
+ status = exit_code & 0x7f;
+ }
+ return wait_noreap_copyout(p, pid, uid, why, status, infop);
+ }
/*
* Try to move the task's state to DEAD
@@ -1001,12 +1049,32 @@ static int wait_task_zombie(task_t *p, u
read_unlock(&tasklist_lock);
retval = ru ? getrusage(p, RUSAGE_BOTH, ru) : 0;
- if (!retval && stat_addr) {
- if (p->signal->group_exit)
- retval = put_user(p->signal->group_exit_code, stat_addr);
- else
- retval = put_user(p->exit_code, stat_addr);
- }
+ status = p->signal->group_exit
+ ? p->signal->group_exit_code : p->exit_code;
+ if (!retval && stat_addr)
+ retval = put_user(status, stat_addr);
+ if (!retval && infop)
+ retval = put_user(SIGCHLD, &infop->si_signo);
+ if (!retval && infop)
+ retval = put_user(0, &infop->si_errno);
+ if (!retval && infop) {
+ int why;
+ if ((status & 0x7f) == 0) {
+ why = CLD_EXITED;
+ status >>= 8;
+ }
+ else {
+ why = (status & 0x80) ? CLD_DUMPED : CLD_KILLED;
+ status &= 0x7f;
+ }
+ retval = put_user((short)why, &infop->si_code);
+ if (!retval)
+ retval = put_user(status, &infop->si_status);
+ }
+ if (!retval && infop)
+ retval = put_user(p->pid, &infop->si_pid);
+ if (!retval && infop)
+ retval = put_user(p->uid, &infop->si_uid);
if (retval) {
p->state = TASK_ZOMBIE;
return retval;
@@ -1042,9 +1110,9 @@ static int wait_task_zombie(task_t *p, u
* 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_stopped(task_t *p, int delayed_group_leader,
- unsigned int __user *stat_addr,
- struct rusage __user *ru)
+static int wait_task_stopped(task_t *p, int delayed_group_leader, int noreap,
+ struct siginfo __user *infop,
+ int __user *stat_addr, struct rusage __user *ru)
{
int retval, exit_code;
@@ -1067,6 +1135,20 @@ static int wait_task_stopped(task_t *p,
*/
get_task_struct(p);
read_unlock(&tasklist_lock);
+
+ if (unlikely(noreap)) {
+ pid_t pid = p->pid;
+ uid_t uid = p->uid;
+ int why = (p->ptrace & PT_PTRACED) ? CLD_TRAPPED : CLD_STOPPED;
+ exit_code = p->exit_code;
+ if (unlikely(!exit_code) ||
+ unlikely(p->state > TASK_STOPPED))
+ goto bail_ref;
+ return wait_noreap_copyout(p, pid, uid,
+ why, (exit_code << 8) | 0x7f,
+ infop);
+ }
+
write_lock_irq(&tasklist_lock);
/*
@@ -1092,6 +1174,7 @@ static int wait_task_stopped(task_t *p,
* resumed, or it resumed and then died.
*/
write_unlock_irq(&tasklist_lock);
+ bail_ref:
put_task_struct(p);
read_lock(&tasklist_lock);
return 0;
@@ -1106,6 +1189,20 @@ static int wait_task_stopped(task_t *p,
retval = ru ? getrusage(p, RUSAGE_BOTH, ru) : 0;
if (!retval && stat_addr)
retval = put_user((exit_code << 8) | 0x7f, stat_addr);
+ if (!retval && infop)
+ retval = put_user(SIGCHLD, &infop->si_signo);
+ if (!retval && infop)
+ retval = put_user(0, &infop->si_errno);
+ if (!retval && infop)
+ retval = put_user((short)((p->ptrace & PT_PTRACED)
+ ? CLD_TRAPPED : CLD_STOPPED),
+ &infop->si_code);
+ if (!retval && infop)
+ retval = put_user(exit_code, &infop->si_status);
+ if (!retval && infop)
+ retval = put_user(p->pid, &infop->si_pid);
+ if (!retval && infop)
+ retval = put_user(p->uid, &infop->si_uid);
if (!retval)
retval = p->pid;
put_task_struct(p);
@@ -1114,15 +1211,13 @@ static int wait_task_stopped(task_t *p,
return retval;
}
-asmlinkage long sys_wait4(pid_t pid,unsigned int __user *stat_addr, int options, struct rusage __user *ru)
+static long do_wait(pid_t pid, int options, struct siginfo __user *infop,
+ int __user *stat_addr, struct rusage __user *ru)
{
DECLARE_WAITQUEUE(wait, current);
struct task_struct *tsk;
int flag, retval;
- if (options & ~(WNOHANG|WUNTRACED|__WNOTHREAD|__WCLONE|__WALL))
- return -EINVAL;
-
add_wait_queue(¤t->wait_chldexit,&wait);
repeat:
flag = 0;
@@ -1148,19 +1243,51 @@ repeat:
!(p->ptrace & PT_PTRACED))
continue;
retval = wait_task_stopped(p, ret == 2,
+ (options & WNOWAIT),
+ infop,
stat_addr, ru);
if (retval != 0) /* He released the lock. */
- goto end_wait4;
+ goto end;
break;
case TASK_ZOMBIE:
/*
* Eligible but we cannot release it yet:
*/
if (ret == 2)
+ goto check_continued;
+ if (!likely(options & WEXITED))
continue;
- retval = wait_task_zombie(p, stat_addr, ru);
+ retval = wait_task_zombie(
+ p, (options & WNOWAIT),
+ infop, stat_addr, ru);
if (retval != 0) /* He released the lock. */
- goto end_wait4;
+ goto end;
+ break;
+ case TASK_DEAD:
+ continue;
+ default:
+ 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;
+ 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);
+ BUG_ON(retval == 0);
+ goto end;
+ }
+ spin_unlock_irq(&p->sighand->siglock);
break;
}
}
@@ -1183,20 +1310,57 @@ repeat:
if (flag) {
retval = 0;
if (options & WNOHANG)
- goto end_wait4;
+ goto end;
retval = -ERESTARTSYS;
if (signal_pending(current))
- goto end_wait4;
+ goto end;
schedule();
goto repeat;
}
retval = -ECHILD;
-end_wait4:
+ end:
current->state = TASK_RUNNING;
remove_wait_queue(¤t->wait_chldexit,&wait);
+ if (infop && retval > 0)
+ retval = 0;
return retval;
}
+asmlinkage long sys_waitid(int which, pid_t pid,
+ struct siginfo __user *infop, int options)
+{
+ if (options & ~(WNOHANG|WNOWAIT|WEXITED|WSTOPPED|WCONTINUED))
+ return -EINVAL;
+ if (!(options & (WEXITED|WSTOPPED|WCONTINUED)))
+ return -EINVAL;
+
+ switch (which) {
+ case P_ALL:
+ pid = -1;
+ break;
+ case P_PID:
+ if (pid <= 0)
+ return -EINVAL;
+ break;
+ case P_PGID:
+ if (pid <= 0)
+ return -EINVAL;
+ pid = -pid;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return do_wait(pid, options, infop, NULL, &infop->si_rusage);
+}
+
+asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru)
+{
+ if (options & ~(WNOHANG|WUNTRACED|__WNOTHREAD|__WCLONE|__WALL))
+ return -EINVAL;
+ return do_wait(pid, options | WEXITED, NULL, stat_addr, ru);
+}
+
#ifdef __ARCH_WANT_SYS_WAITPID
/*
--- vanilla-linux-2.6/kernel/signal.c 2004-07-06 23:25:36.000000000 -0700
+++ linux-2.6/kernel/signal.c 2004-08-05 14:49:46.000000000 -0700
@@ -26,6 +26,8 @@
#include <asm/unistd.h>
#include <asm/siginfo.h>
+extern void k_getrusage(struct task_struct *, int, struct rusage *);
+
/*
* SLAB caches for signal bits.
*/
@@ -660,6 +662,7 @@ static void handle_stop_signal(int sig,
* the SIGCHLD was pending on entry to this kill.
*/
p->signal->group_stop_count = 0;
+ p->signal->stop_state = 1;
if (p->ptrace & PT_PTRACED)
do_notify_parent_cldstop(p, p->parent);
else
@@ -696,6 +699,21 @@ static void handle_stop_signal(int sig,
t = next_thread(t);
} while (t != p);
+
+ if (p->signal->stop_state > 0) {
+ /*
+ * We were in fact stopped, and are now continued.
+ * Notify the parent with CLD_CONTINUED.
+ */
+ p->signal->stop_state = -1;
+ p->signal->group_exit_code = 0;
+ if (p->ptrace & PT_PTRACED)
+ do_notify_parent_cldstop(p, p->parent);
+ else
+ do_notify_parent_cldstop(
+ p->group_leader,
+ p->group_leader->real_parent);
+ }
}
}
@@ -1447,6 +1465,7 @@ void do_notify_parent(struct task_struct
/* FIXME: find out whether or not this is supposed to be c*time. */
info.si_utime = tsk->utime;
info.si_stime = tsk->stime;
+ k_getrusage(tsk, RUSAGE_BOTH, &info.si_rusage);
status = tsk->exit_code & 0x7f;
why = SI_KERNEL; /* shouldn't happen */
@@ -1536,9 +1555,16 @@ do_notify_parent_cldstop(struct task_str
/* FIXME: find out whether or not this is supposed to be c*time. */
info.si_utime = tsk->utime;
info.si_stime = tsk->stime;
+ k_getrusage(tsk, RUSAGE_BOTH, &info.si_rusage);
- info.si_status = tsk->exit_code & 0x7f;
- info.si_code = CLD_STOPPED;
+ info.si_status = (tsk->signal ? tsk->signal->group_exit_code :
+ tsk->exit_code) & 0x7f;
+ if (info.si_status == 0) {
+ info.si_status = SIGCONT;
+ info.si_code = CLD_CONTINUED;
+ }
+ else
+ info.si_code = CLD_STOPPED;
sighand = parent->sighand;
spin_lock_irqsave(&sighand->siglock, flags);
@@ -1604,14 +1630,17 @@ do_signal_stop(int signr)
stop_count = --sig->group_stop_count;
current->exit_code = signr;
set_current_state(TASK_STOPPED);
+ if (stop_count == 0)
+ sig->stop_state = 1;
spin_unlock_irq(&sighand->siglock);
}
else if (thread_group_empty(current)) {
/*
* Lock must be held through transition to stopped state.
*/
- current->exit_code = signr;
+ current->exit_code = current->signal->group_exit_code = signr;
set_current_state(TASK_STOPPED);
+ sig->stop_state = 1;
spin_unlock_irq(&sighand->siglock);
}
else {
@@ -1677,6 +1706,8 @@ do_signal_stop(int signr)
current->exit_code = signr;
set_current_state(TASK_STOPPED);
+ if (stop_count == 0)
+ sig->stop_state = 1;
spin_unlock_irq(&sighand->siglock);
read_unlock(&tasklist_lock);
@@ -1717,6 +1748,8 @@ static inline int handle_group_stop(void
* without any associated signal being in our queue.
*/
stop_count = --current->signal->group_stop_count;
+ if (stop_count == 0)
+ current->signal->stop_state = 1;
current->exit_code = current->signal->group_exit_code;
set_current_state(TASK_STOPPED);
spin_unlock_irq(¤t->sighand->siglock);
@@ -2071,6 +2104,8 @@ int copy_siginfo_to_user(siginfo_t __use
err |= __put_user(from->si_status, &to->si_status);
err |= __put_user(from->si_utime, &to->si_utime);
err |= __put_user(from->si_stime, &to->si_stime);
+ err |= __copy_to_user(&to->si_rusage, &from->si_rusage,
+ sizeof(to->si_rusage));
break;
case __SI_RT: /* This is not generated by the kernel as of now. */
case __SI_MESGQ: /* But this is */
--- vanilla-linux-2.6/kernel/sys.c 2004-06-01 08:35:45.000000000 -0700
+++ linux-2.6/kernel/sys.c 2004-08-04 01:10:51.000000000 -0700
@@ -1540,37 +1540,43 @@ asmlinkage long sys_setrlimit(unsigned i
* reaped till shortly after the call to getrusage(), in both cases the
* task being examined is in a frozen state so the counters won't change.
*/
-int getrusage(struct task_struct *p, int who, struct rusage __user *ru)
-{
- struct rusage r;
- memset((char *) &r, 0, sizeof(r));
+
+void k_getrusage(struct task_struct *p, int who, struct rusage *r)
+{
+ memset((char *) r, 0, sizeof *r);
switch (who) {
case RUSAGE_SELF:
- jiffies_to_timeval(p->utime, &r.ru_utime);
- jiffies_to_timeval(p->stime, &r.ru_stime);
- r.ru_nvcsw = p->nvcsw;
- r.ru_nivcsw = p->nivcsw;
- r.ru_minflt = p->min_flt;
- r.ru_majflt = p->maj_flt;
+ jiffies_to_timeval(p->utime, &r->ru_utime);
+ jiffies_to_timeval(p->stime, &r->ru_stime);
+ r->ru_nvcsw = p->nvcsw;
+ r->ru_nivcsw = p->nivcsw;
+ r->ru_minflt = p->min_flt;
+ r->ru_majflt = p->maj_flt;
break;
case RUSAGE_CHILDREN:
- jiffies_to_timeval(p->cutime, &r.ru_utime);
- jiffies_to_timeval(p->cstime, &r.ru_stime);
- r.ru_nvcsw = p->cnvcsw;
- r.ru_nivcsw = p->cnivcsw;
- r.ru_minflt = p->cmin_flt;
- r.ru_majflt = p->cmaj_flt;
+ jiffies_to_timeval(p->cutime, &r->ru_utime);
+ jiffies_to_timeval(p->cstime, &r->ru_stime);
+ r->ru_nvcsw = p->cnvcsw;
+ r->ru_nivcsw = p->cnivcsw;
+ r->ru_minflt = p->cmin_flt;
+ r->ru_majflt = p->cmaj_flt;
break;
default:
- jiffies_to_timeval(p->utime + p->cutime, &r.ru_utime);
- jiffies_to_timeval(p->stime + p->cstime, &r.ru_stime);
- r.ru_nvcsw = p->nvcsw + p->cnvcsw;
- r.ru_nivcsw = p->nivcsw + p->cnivcsw;
- r.ru_minflt = p->min_flt + p->cmin_flt;
- r.ru_majflt = p->maj_flt + p->cmaj_flt;
+ jiffies_to_timeval(p->utime + p->cutime, &r->ru_utime);
+ jiffies_to_timeval(p->stime + p->cstime, &r->ru_stime);
+ r->ru_nvcsw = p->nvcsw + p->cnvcsw;
+ r->ru_nivcsw = p->nivcsw + p->cnivcsw;
+ r->ru_minflt = p->min_flt + p->cmin_flt;
+ r->ru_majflt = p->maj_flt + p->cmaj_flt;
break;
}
+}
+
+int getrusage(struct task_struct *p, int who, struct rusage __user *ru)
+{
+ struct rusage r;
+ k_getrusage(p, who, &r);
return copy_to_user(ru, &r, sizeof(r)) ? -EFAULT : 0;
}
^ permalink raw reply [flat|nested] 22+ messages in thread* Re: [PATCH] waitid system call 2004-08-15 23:03 [PATCH] waitid system call Roland McGrath @ 2004-08-16 5:40 ` Roland McGrath 2004-08-16 17:15 ` Michael Kerrisk 0 siblings, 1 reply; 22+ messages in thread From: Roland McGrath @ 2004-08-16 5:40 UTC (permalink / raw) To: Linus Torvalds, Andrew Morton; +Cc: Ulrich Drepper, Linux Kernel Mailing List This is an updated version of the waitid patch that fixes some things that people pointed out to me. To do the 64->32 struct rusage field correctly, I made the static function put_compat_rusage from linux/compat.c global and swapped its argument order to match the other public functions of that form. Thanks, Roland Signed-off-by: Roland McGrath <roland@redhat.com> --- vanilla-linux-2.6/arch/i386/kernel/entry.S 2004-05-22 22:03:15.000000000 -0700 +++ linux-2.6/arch/i386/kernel/entry.S 2004-07-12 14:03:36.000000000 -0700 @@ -886,5 +886,6 @@ ENTRY(sys_call_table) .long sys_mq_notify .long sys_mq_getsetattr .long sys_ni_syscall /* reserved for kexec */ + .long sys_waitid syscall_table_size=(.-sys_call_table) --- vanilla-linux-2.6/arch/x86_64/ia32/ia32_signal.c 2004-07-13 11:02:33.000000000 -0700 +++ linux-2.6/arch/x86_64/ia32/ia32_signal.c 2004-08-15 18:58:27.000000000 -0700 @@ -74,6 +74,8 @@ int ia32_copy_siginfo_to_user(siginfo_t3 err |= __put_user(from->si_utime, &to->si_utime); err |= __put_user(from->si_stime, &to->si_stime); err |= __put_user(from->si_status, &to->si_status); + err |= put_compat_rusage(&from->si_rusage, + &to->si_rusage); default: case __SI_KILL >> 16: err |= __put_user(from->si_uid, &to->si_uid); --- vanilla-linux-2.6/arch/x86_64/ia32/ia32entry.S 2004-05-30 11:55:13.000000000 -0700 +++ linux-2.6/arch/x86_64/ia32/ia32entry.S 2004-08-09 23:56:06.000000000 -0700 @@ -589,6 +589,7 @@ ia32_sys_call_table: .quad compat_sys_mq_notify .quad compat_sys_mq_getsetattr .quad quiet_ni_syscall /* reserved for kexec */ + .quad sys32_waitid /* don't forget to change IA32_NR_syscalls */ ia32_syscall_end: .rept IA32_NR_syscalls-(ia32_syscall_end-ia32_sys_call_table)/8 --- vanilla-linux-2.6/arch/x86_64/ia32/sys_ia32.c 2004-07-30 22:49:36.000000000 -0700 +++ linux-2.6/arch/x86_64/ia32/sys_ia32.c 2004-08-11 12:01:41.000000000 -0700 @@ -1151,6 +1151,25 @@ asmlinkage long sys32_clone(unsigned int parent_tid, child_tid); } +asmlinkage long sys32_waitid(int which, compat_pid_t pid, + siginfo_t32 __user *uinfo, int options) +{ + siginfo_t info; + long ret; + mm_segment_t old_fs = get_fs(); + + info.si_signo = 0; + set_fs (KERNEL_DS); + ret = sys_waitid(which, pid, (siginfo_t __user *) &info, options); + set_fs (old_fs); + + if (ret < 0 || info.si_signo == 0) + return ret; + BUG_ON(info.si_code & __SI_MASK); + info.si_code |= __SI_CHLD; + return ia32_copy_siginfo_to_user(uinfo, &info); +} + /* * Some system calls that need sign extended arguments. This could be done by a generic wrapper. */ --- vanilla-linux-2.6/include/asm-generic/siginfo.h 2004-07-13 11:02:33.000000000 -0700 +++ linux-2.6/include/asm-generic/siginfo.h 2004-07-15 14:20:56.000000000 -0700 @@ -3,6 +3,7 @@ #include <linux/compiler.h> #include <linux/types.h> +#include <linux/resource.h> typedef union sigval { int sival_int; @@ -74,6 +75,7 @@ typedef struct siginfo { int _status; /* exit code */ clock_t _utime; clock_t _stime; + struct rusage _rusage; } _sigchld; /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ @@ -105,6 +107,7 @@ typedef struct siginfo { #define si_status _sifields._sigchld._status #define si_utime _sifields._sigchld._utime #define si_stime _sifields._sigchld._stime +#define si_rusage _sifields._sigchld._rusage #define si_value _sifields._rt._sigval #define si_int _sifields._rt._sigval.sival_int #define si_ptr _sifields._rt._sigval.sival_ptr --- vanilla-linux-2.6/include/asm-i386/unistd.h 2004-08-02 10:14:04.000000000 -0700 +++ linux-2.6/include/asm-i386/unistd.h 2004-08-04 00:18:53.000000000 -0700 @@ -289,8 +289,9 @@ #define __NR_mq_notify (__NR_mq_open+4) #define __NR_mq_getsetattr (__NR_mq_open+5) #define __NR_sys_kexec_load 283 +#define __NR_waitid 284 -#define NR_syscalls 284 +#define NR_syscalls 285 /* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */ --- vanilla-linux-2.6/include/asm-x86_64/ia32.h 2004-05-30 20:07:42.000000000 -0700 +++ linux-2.6/include/asm-x86_64/ia32.h 2004-08-09 21:13:30.000000000 -0700 @@ -121,6 +121,7 @@ typedef struct siginfo32 { int _status; /* exit code */ compat_clock_t _utime; compat_clock_t _stime; + struct compat_rusage _rusage; } _sigchld; /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ --- vanilla-linux-2.6/include/asm-x86_64/ia32_unistd.h 2004-05-30 11:55:13.000000000 -0700 +++ linux-2.6/include/asm-x86_64/ia32_unistd.h 2004-07-26 17:59:32.000000000 -0700 @@ -289,6 +289,7 @@ #define __NR_ia32_mq_notify (__NR_ia32_mq_open+4) #define __NR_ia32_mq_getsetattr (__NR_ia32_mq_open+5) #define __NR_ia32_kexec 283 +#define __NR_ia32_waitid 284 #define IA32_NR_syscalls 287 /* must be > than biggest syscall! */ --- vanilla-linux-2.6/include/asm-x86_64/unistd.h 2004-06-09 08:17:36.000000000 -0700 +++ linux-2.6/include/asm-x86_64/unistd.h 2004-07-26 15:44:13.000000000 -0700 @@ -554,8 +554,10 @@ __SYSCALL(__NR_mq_notify, sys_mq_notify) __SYSCALL(__NR_mq_getsetattr, sys_mq_getsetattr) #define __NR_kexec_load 246 __SYSCALL(__NR_kexec_load, sys_ni_syscall) +#define __NR_waitid 247 +__SYSCALL(__NR_waitid, sys_waitid) -#define __NR_syscall_max __NR_kexec_load +#define __NR_syscall_max __NR_waitid #ifndef __NO_STUBS /* user-visible error numbers are in the range -1 - -4095 */ --- vanilla-linux-2.6/include/linux/compat.h 2004-05-29 11:15:01.000000000 -0700 +++ linux-2.6/include/linux/compat.h 2004-08-15 21:15:59.791627829 -0700 @@ -79,6 +79,8 @@ struct compat_rusage { compat_long_t ru_nivcsw; }; +extern int put_compat_rusage(const struct rusage *, struct compat_rusage __user *); + struct compat_dirent { u32 d_ino; compat_off_t d_off; --- vanilla-linux-2.6/include/linux/sched.h 2004-07-28 23:13:51.000000000 -0700 +++ linux-2.6/include/linux/sched.h 2004-08-05 13:46:40.000000000 -0700 @@ -268,6 +268,8 @@ struct signal_struct { /* thread group stop support, overloads group_exit_code too */ int group_stop_count; + /* 1 if group stopped since last SIGCONT, -1 if SIGCONT since report */ + int stop_state; /* POSIX.1b Interval Timers */ struct list_head posix_timers; --- vanilla-linux-2.6/include/linux/syscalls.h 2004-06-22 08:27:43.000000000 -0700 +++ linux-2.6/include/linux/syscalls.h 2004-08-09 23:44:22.000000000 -0700 @@ -162,6 +162,8 @@ asmlinkage long sys_exit(int error_code) asmlinkage void sys_exit_group(int error_code); asmlinkage long sys_wait4(pid_t pid, unsigned int __user *stat_addr, int options, struct rusage __user *ru); +asmlinkage long sys_waitid(int which, pid_t pid, + struct siginfo __user *infop, int options); asmlinkage long sys_waitpid(pid_t pid, unsigned int __user *stat_addr, int options); asmlinkage long sys_set_tid_address(int __user *tidptr); asmlinkage long sys_futex(u32 __user *uaddr, int op, int val, --- vanilla-linux-2.6/include/linux/wait.h 2004-06-24 08:54:26.000000000 -0700 +++ linux-2.6/include/linux/wait.h 2004-07-01 22:56:27.000000000 -0700 @@ -3,11 +3,20 @@ #define WNOHANG 0x00000001 #define WUNTRACED 0x00000002 +#define WSTOPPED WUNTRACED +#define WEXITED 0x00000004 +#define WCONTINUED 0x00000008 +#define WNOWAIT 0x01000000 /* Don't reap, just poll status. */ #define __WNOTHREAD 0x20000000 /* Don't wait on children of other threads in this group */ #define __WALL 0x40000000 /* Wait on all children, regardless of type */ #define __WCLONE 0x80000000 /* Wait only on non-SIGCHLD children */ +/* First argument to waitid: */ +#define P_ALL 0 +#define P_PID 1 +#define P_PGID 2 + #ifdef __KERNEL__ #include <linux/config.h> --- vanilla-linux-2.6/kernel/compat.c 2004-07-28 22:57:26.000000000 -0700 +++ linux-2.6/kernel/compat.c 2004-08-15 19:13:15.000000000 -0700 @@ -310,7 +310,7 @@ asmlinkage long compat_sys_getrlimit (un return ret; } -static long put_compat_rusage(struct compat_rusage __user *ru, struct rusage *r) +int put_compat_rusage(const struct rusage *r, struct compat_rusage __user *ru) { if (!access_ok(VERIFY_WRITE, ru, sizeof(*ru)) || __put_user(r->ru_utime.tv_sec, &ru->ru_utime.tv_sec) || @@ -348,7 +348,7 @@ asmlinkage long compat_sys_getrusage(int if (ret) return ret; - if (put_compat_rusage(ru, &r)) + if (put_compat_rusage(&r, ru)) return -EFAULT; return 0; @@ -374,7 +374,7 @@ compat_sys_wait4(compat_pid_t pid, compa set_fs (old_fs); if (ret > 0) { - if (put_compat_rusage(ru, &r)) + if (put_compat_rusage(&r, ru)) return -EFAULT; if (stat_addr && put_user(status, stat_addr)) return -EFAULT; --- vanilla-linux-2.6/kernel/exit.c 2004-07-17 21:51:57.000000000 -0700 +++ linux-2.6/kernel/exit.c 2004-08-15 19:13:54.000000000 -0700 @@ -967,16 +967,64 @@ static int eligible_child(pid_t pid, int return 1; } +static int wait_noreap_copyout(task_t *p, pid_t pid, uid_t uid, + int why, int status, + struct siginfo __user *infop) +{ + int retval = getrusage(p, RUSAGE_BOTH, &infop->si_rusage); + put_task_struct(p); + if (!retval) + retval = put_user(SIGCHLD, &infop->si_signo); + if (!retval) + retval = put_user(0, &infop->si_errno); + if (!retval) + retval = put_user((short)why, &infop->si_code); + if (!retval) + retval = put_user(pid, &infop->si_pid); + if (!retval) + retval = put_user(uid, &infop->si_uid); + if (!retval) + retval = put_user(status, &infop->si_status); + if (!retval) + retval = pid; + return retval; +} + /* * Handle sys_wait4 work for one task in state TASK_ZOMBIE. We hold * 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_zombie(task_t *p, unsigned int __user *stat_addr, struct rusage __user *ru) +static int wait_task_zombie(task_t *p, int noreap, + struct siginfo __user *infop, + int __user *stat_addr, struct rusage __user *ru) { unsigned long state; int retval; + int status; + + if (unlikely(noreap)) { + pid_t pid = p->pid; + uid_t uid = p->uid; + int exit_code = p->exit_code; + int why, status; + if (unlikely(p->state != TASK_ZOMBIE)) + return 0; + if (unlikely(p->exit_signal == -1 && p->ptrace == 0)) + return 0; + get_task_struct(p); + read_unlock(&tasklist_lock); + if ((exit_code & 0x7f) == 0) { + why = CLD_EXITED; + status = exit_code >> 8; + } + else { + why = (exit_code & 0x80) ? CLD_DUMPED : CLD_KILLED; + status = exit_code & 0x7f; + } + return wait_noreap_copyout(p, pid, uid, why, status, infop); + } /* * Try to move the task's state to DEAD @@ -1001,12 +1049,32 @@ static int wait_task_zombie(task_t *p, u read_unlock(&tasklist_lock); retval = ru ? getrusage(p, RUSAGE_BOTH, ru) : 0; - if (!retval && stat_addr) { - if (p->signal->group_exit) - retval = put_user(p->signal->group_exit_code, stat_addr); - else - retval = put_user(p->exit_code, stat_addr); - } + status = p->signal->group_exit + ? p->signal->group_exit_code : p->exit_code; + if (!retval && stat_addr) + retval = put_user(status, stat_addr); + if (!retval && infop) + retval = put_user(SIGCHLD, &infop->si_signo); + if (!retval && infop) + retval = put_user(0, &infop->si_errno); + if (!retval && infop) { + int why; + if ((status & 0x7f) == 0) { + why = CLD_EXITED; + status >>= 8; + } + else { + why = (status & 0x80) ? CLD_DUMPED : CLD_KILLED; + status &= 0x7f; + } + retval = put_user((short)why, &infop->si_code); + if (!retval) + retval = put_user(status, &infop->si_status); + } + if (!retval && infop) + retval = put_user(p->pid, &infop->si_pid); + if (!retval && infop) + retval = put_user(p->uid, &infop->si_uid); if (retval) { p->state = TASK_ZOMBIE; return retval; @@ -1042,9 +1110,9 @@ static int wait_task_zombie(task_t *p, u * 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_stopped(task_t *p, int delayed_group_leader, - unsigned int __user *stat_addr, - struct rusage __user *ru) +static int wait_task_stopped(task_t *p, int delayed_group_leader, int noreap, + struct siginfo __user *infop, + int __user *stat_addr, struct rusage __user *ru) { int retval, exit_code; @@ -1067,6 +1135,20 @@ static int wait_task_stopped(task_t *p, */ get_task_struct(p); read_unlock(&tasklist_lock); + + if (unlikely(noreap)) { + pid_t pid = p->pid; + uid_t uid = p->uid; + int why = (p->ptrace & PT_PTRACED) ? CLD_TRAPPED : CLD_STOPPED; + exit_code = p->exit_code; + if (unlikely(!exit_code) || + unlikely(p->state > TASK_STOPPED)) + goto bail_ref; + return wait_noreap_copyout(p, pid, uid, + why, (exit_code << 8) | 0x7f, + infop); + } + write_lock_irq(&tasklist_lock); /* @@ -1092,6 +1174,7 @@ static int wait_task_stopped(task_t *p, * resumed, or it resumed and then died. */ write_unlock_irq(&tasklist_lock); + bail_ref: put_task_struct(p); read_lock(&tasklist_lock); return 0; @@ -1106,6 +1189,20 @@ static int wait_task_stopped(task_t *p, retval = ru ? getrusage(p, RUSAGE_BOTH, ru) : 0; if (!retval && stat_addr) retval = put_user((exit_code << 8) | 0x7f, stat_addr); + if (!retval && infop) + retval = put_user(SIGCHLD, &infop->si_signo); + if (!retval && infop) + retval = put_user(0, &infop->si_errno); + if (!retval && infop) + retval = put_user((short)((p->ptrace & PT_PTRACED) + ? CLD_TRAPPED : CLD_STOPPED), + &infop->si_code); + if (!retval && infop) + retval = put_user(exit_code, &infop->si_status); + if (!retval && infop) + retval = put_user(p->pid, &infop->si_pid); + if (!retval && infop) + retval = put_user(p->uid, &infop->si_uid); if (!retval) retval = p->pid; put_task_struct(p); @@ -1114,15 +1211,13 @@ static int wait_task_stopped(task_t *p, return retval; } -asmlinkage long sys_wait4(pid_t pid,unsigned int __user *stat_addr, int options, struct rusage __user *ru) +static long do_wait(pid_t pid, int options, struct siginfo __user *infop, + int __user *stat_addr, struct rusage __user *ru) { DECLARE_WAITQUEUE(wait, current); struct task_struct *tsk; int flag, retval; - if (options & ~(WNOHANG|WUNTRACED|__WNOTHREAD|__WCLONE|__WALL)) - return -EINVAL; - add_wait_queue(¤t->wait_chldexit,&wait); repeat: flag = 0; @@ -1148,19 +1243,52 @@ repeat: !(p->ptrace & PT_PTRACED)) continue; retval = wait_task_stopped(p, ret == 2, + (options & WNOWAIT), + infop, stat_addr, ru); if (retval != 0) /* He released the lock. */ - goto end_wait4; + goto end; break; case TASK_ZOMBIE: /* * Eligible but we cannot release it yet: */ if (ret == 2) + goto check_continued; + if (!likely(options & WEXITED)) continue; - retval = wait_task_zombie(p, stat_addr, ru); + retval = wait_task_zombie( + p, (options & WNOWAIT), + infop, stat_addr, ru); if (retval != 0) /* He released the lock. */ - goto end_wait4; + goto end; + break; + case TASK_DEAD: + continue; + default: + 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); + BUG_ON(retval == 0); + goto end; + } + spin_unlock_irq(&p->sighand->siglock); break; } } @@ -1183,20 +1311,57 @@ repeat: if (flag) { retval = 0; if (options & WNOHANG) - goto end_wait4; + goto end; retval = -ERESTARTSYS; if (signal_pending(current)) - goto end_wait4; + goto end; schedule(); goto repeat; } retval = -ECHILD; -end_wait4: + end: current->state = TASK_RUNNING; remove_wait_queue(¤t->wait_chldexit,&wait); + if (infop && retval > 0) + retval = 0; return retval; } +asmlinkage long sys_waitid(int which, pid_t pid, + struct siginfo __user *infop, int options) +{ + if (options & ~(WNOHANG|WNOWAIT|WEXITED|WSTOPPED|WCONTINUED)) + return -EINVAL; + if (!(options & (WEXITED|WSTOPPED|WCONTINUED))) + return -EINVAL; + + switch (which) { + case P_ALL: + pid = -1; + break; + case P_PID: + if (pid <= 0) + return -EINVAL; + break; + case P_PGID: + if (pid <= 0) + return -EINVAL; + pid = -pid; + break; + default: + return -EINVAL; + } + + return do_wait(pid, options, infop, NULL, &infop->si_rusage); +} + +asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru) +{ + if (options & ~(WNOHANG|WUNTRACED|__WNOTHREAD|__WCLONE|__WALL)) + return -EINVAL; + return do_wait(pid, options | WEXITED, NULL, stat_addr, ru); +} + #ifdef __ARCH_WANT_SYS_WAITPID /* --- vanilla-linux-2.6/kernel/signal.c 2004-07-06 23:25:36.000000000 -0700 +++ linux-2.6/kernel/signal.c 2004-08-05 14:49:46.000000000 -0700 @@ -26,6 +26,8 @@ #include <asm/unistd.h> #include <asm/siginfo.h> +extern void k_getrusage(struct task_struct *, int, struct rusage *); + /* * SLAB caches for signal bits. */ @@ -660,6 +662,7 @@ static void handle_stop_signal(int sig, * the SIGCHLD was pending on entry to this kill. */ p->signal->group_stop_count = 0; + p->signal->stop_state = 1; if (p->ptrace & PT_PTRACED) do_notify_parent_cldstop(p, p->parent); else @@ -696,6 +699,21 @@ static void handle_stop_signal(int sig, t = next_thread(t); } while (t != p); + + if (p->signal->stop_state > 0) { + /* + * We were in fact stopped, and are now continued. + * Notify the parent with CLD_CONTINUED. + */ + p->signal->stop_state = -1; + p->signal->group_exit_code = 0; + if (p->ptrace & PT_PTRACED) + do_notify_parent_cldstop(p, p->parent); + else + do_notify_parent_cldstop( + p->group_leader, + p->group_leader->real_parent); + } } } @@ -1447,6 +1465,7 @@ void do_notify_parent(struct task_struct /* FIXME: find out whether or not this is supposed to be c*time. */ info.si_utime = tsk->utime; info.si_stime = tsk->stime; + k_getrusage(tsk, RUSAGE_BOTH, &info.si_rusage); status = tsk->exit_code & 0x7f; why = SI_KERNEL; /* shouldn't happen */ @@ -1536,9 +1555,16 @@ do_notify_parent_cldstop(struct task_str /* FIXME: find out whether or not this is supposed to be c*time. */ info.si_utime = tsk->utime; info.si_stime = tsk->stime; + k_getrusage(tsk, RUSAGE_BOTH, &info.si_rusage); - info.si_status = tsk->exit_code & 0x7f; - info.si_code = CLD_STOPPED; + info.si_status = (tsk->signal ? tsk->signal->group_exit_code : + tsk->exit_code) & 0x7f; + if (info.si_status == 0) { + info.si_status = SIGCONT; + info.si_code = CLD_CONTINUED; + } + else + info.si_code = CLD_STOPPED; sighand = parent->sighand; spin_lock_irqsave(&sighand->siglock, flags); @@ -1604,14 +1630,17 @@ do_signal_stop(int signr) stop_count = --sig->group_stop_count; current->exit_code = signr; set_current_state(TASK_STOPPED); + if (stop_count == 0) + sig->stop_state = 1; spin_unlock_irq(&sighand->siglock); } else if (thread_group_empty(current)) { /* * Lock must be held through transition to stopped state. */ - current->exit_code = signr; + current->exit_code = current->signal->group_exit_code = signr; set_current_state(TASK_STOPPED); + sig->stop_state = 1; spin_unlock_irq(&sighand->siglock); } else { @@ -1677,6 +1706,8 @@ do_signal_stop(int signr) current->exit_code = signr; set_current_state(TASK_STOPPED); + if (stop_count == 0) + sig->stop_state = 1; spin_unlock_irq(&sighand->siglock); read_unlock(&tasklist_lock); @@ -1717,6 +1748,8 @@ static inline int handle_group_stop(void * without any associated signal being in our queue. */ stop_count = --current->signal->group_stop_count; + if (stop_count == 0) + current->signal->stop_state = 1; current->exit_code = current->signal->group_exit_code; set_current_state(TASK_STOPPED); spin_unlock_irq(¤t->sighand->siglock); @@ -2071,6 +2104,8 @@ int copy_siginfo_to_user(siginfo_t __use err |= __put_user(from->si_status, &to->si_status); err |= __put_user(from->si_utime, &to->si_utime); err |= __put_user(from->si_stime, &to->si_stime); + err |= __copy_to_user(&to->si_rusage, &from->si_rusage, + sizeof(to->si_rusage)); break; case __SI_RT: /* This is not generated by the kernel as of now. */ case __SI_MESGQ: /* But this is */ --- vanilla-linux-2.6/kernel/sys.c 2004-06-01 08:35:45.000000000 -0700 +++ linux-2.6/kernel/sys.c 2004-08-04 01:10:51.000000000 -0700 @@ -1540,37 +1540,43 @@ asmlinkage long sys_setrlimit(unsigned i * reaped till shortly after the call to getrusage(), in both cases the * task being examined is in a frozen state so the counters won't change. */ -int getrusage(struct task_struct *p, int who, struct rusage __user *ru) -{ - struct rusage r; - memset((char *) &r, 0, sizeof(r)); + +void k_getrusage(struct task_struct *p, int who, struct rusage *r) +{ + memset((char *) r, 0, sizeof *r); switch (who) { case RUSAGE_SELF: - jiffies_to_timeval(p->utime, &r.ru_utime); - jiffies_to_timeval(p->stime, &r.ru_stime); - r.ru_nvcsw = p->nvcsw; - r.ru_nivcsw = p->nivcsw; - r.ru_minflt = p->min_flt; - r.ru_majflt = p->maj_flt; + jiffies_to_timeval(p->utime, &r->ru_utime); + jiffies_to_timeval(p->stime, &r->ru_stime); + r->ru_nvcsw = p->nvcsw; + r->ru_nivcsw = p->nivcsw; + r->ru_minflt = p->min_flt; + r->ru_majflt = p->maj_flt; break; case RUSAGE_CHILDREN: - jiffies_to_timeval(p->cutime, &r.ru_utime); - jiffies_to_timeval(p->cstime, &r.ru_stime); - r.ru_nvcsw = p->cnvcsw; - r.ru_nivcsw = p->cnivcsw; - r.ru_minflt = p->cmin_flt; - r.ru_majflt = p->cmaj_flt; + jiffies_to_timeval(p->cutime, &r->ru_utime); + jiffies_to_timeval(p->cstime, &r->ru_stime); + r->ru_nvcsw = p->cnvcsw; + r->ru_nivcsw = p->cnivcsw; + r->ru_minflt = p->cmin_flt; + r->ru_majflt = p->cmaj_flt; break; default: - jiffies_to_timeval(p->utime + p->cutime, &r.ru_utime); - jiffies_to_timeval(p->stime + p->cstime, &r.ru_stime); - r.ru_nvcsw = p->nvcsw + p->cnvcsw; - r.ru_nivcsw = p->nivcsw + p->cnivcsw; - r.ru_minflt = p->min_flt + p->cmin_flt; - r.ru_majflt = p->maj_flt + p->cmaj_flt; + jiffies_to_timeval(p->utime + p->cutime, &r->ru_utime); + jiffies_to_timeval(p->stime + p->cstime, &r->ru_stime); + r->ru_nvcsw = p->nvcsw + p->cnvcsw; + r->ru_nivcsw = p->nivcsw + p->cnivcsw; + r->ru_minflt = p->min_flt + p->cmin_flt; + r->ru_majflt = p->maj_flt + p->cmaj_flt; break; } +} + +int getrusage(struct task_struct *p, int who, struct rusage __user *ru) +{ + struct rusage r; + k_getrusage(p, who, &r); return copy_to_user(ru, &r, sizeof(r)) ? -EFAULT : 0; } ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH] waitid system call 2004-08-16 5:40 ` Roland McGrath @ 2004-08-16 17:15 ` Michael Kerrisk 2004-08-16 21:12 ` Roland McGrath 0 siblings, 1 reply; 22+ messages in thread From: Michael Kerrisk @ 2004-08-16 17:15 UTC (permalink / raw) To: Roland McGrath; +Cc: torvalds, akpm, drepper, linux-kernel [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #1: Type: text/plain; charset="us-ascii", Size: 568 bytes --] > This is an updated version of the waitid patch that fixes some things Roland, Precisely what kernel version was the patch against? I've (twice) tried applying the patch against 2.6.8.1 and building the kernel. The build succeeds, but I am running into a strange kernel panic ("Unable to mount root fs") when I try to boot the resulting kernel. (Compiling and booting 2.6.8.1 on the same x86 machine works fine.) Cheers, Michael -- NEU: WLAN-Router für 0,- EUR* - auch für DSL-Wechsler! GMX DSL = supergünstig & kabellos http://www.gmx.net/de/go/dsl ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH] waitid system call 2004-08-16 17:15 ` Michael Kerrisk @ 2004-08-16 21:12 ` Roland McGrath 2004-08-19 17:20 ` Michael Kerrisk 0 siblings, 1 reply; 22+ messages in thread From: Roland McGrath @ 2004-08-16 21:12 UTC (permalink / raw) To: Michael Kerrisk; +Cc: torvalds, akpm, drepper, linux-kernel > Precisely what kernel version was the patch against? It is against 2.6.8.1. > I've (twice) tried applying the patch against 2.6.8.1 and building the > kernel. The build succeeds, but I am running into a strange kernel panic > ("Unable to mount root fs") when I try to boot the resulting kernel. > (Compiling and booting 2.6.8.1 on the same x86 machine works fine.) Well, it sure works fine for me. Unless someone else can reproduce your issue, you'll have to look into it yourself. I don't discount the likelihood it's a bug caused by my patch, but such an error is so far afield that there is no way for me to guess at what you might be seeing. Thanks, Roland ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH] waitid system call 2004-08-16 21:12 ` Roland McGrath @ 2004-08-19 17:20 ` Michael Kerrisk 2004-08-19 20:53 ` Roland McGrath 0 siblings, 1 reply; 22+ messages in thread From: Michael Kerrisk @ 2004-08-19 17:20 UTC (permalink / raw) To: Roland McGrath; +Cc: torvalds, akpm, drepper, linux-kernel, michael.kerrisk Roland, > > Precisely what kernel version was the patch against? > > It is against 2.6.8.1. > > > I've (twice) tried applying the patch against 2.6.8.1 and building the > > kernel. The build succeeds, but I am running into a strange kernel panic > > ("Unable to mount root fs") when I try to boot the resulting kernel. > > (Compiling and booting 2.6.8.1 on the same x86 machine works fine.) > > Well, it sure works fine for me. Unless someone else can reproduce your > issue, you'll have to look into it yourself. I don't discount the > likelihood it's a bug caused by my patch, but such an error is so far > afield that there is no way for me to guess at what you might be seeing. Yes, I assumed it would work for you ;-). Sorry, I applied 2.6.8* against an existing (near vanilla) 2.6.7 tree in which I didn't realise I'd tweaked some file system support stuff. I've now built against a truly vanilla 2.6.8.1 and it builds and boots fine. I've tested out various things (see below for a summary), and all seems well, with one possible doubt. How can one distinguish "no children to wait for case" and the "child successfully waited for case" when using WNOHANG? SUSv3 is a bit silent on this point, but the Solaris man page helpfully says: If WNOHANG was used, 0 can be returned (indicating no error); however, no children may have changed state if info->si_pid is 0. And testing (program below), shows that this is indeed what happens on Solaris 8. As things stand, this doesn't seem to happen with your patch for Linux -- it would perhaps be nice if it did. Here's what I see when I run the test program at the end of this message (here, the command requests options as WSTOPPED|WEXITED|WCONTINUED|WNOHANG, and creates two children each of which for the specified number of seconds); $ ./waitid_test secH 1 2 child 1 PID=28443 started child 2 PID=28444 started 0: waitid() returned 0 si_pid=1073838904; si_uid=-1073746612; si_status=1 si_code=1073838488 (????); si_signo=-1073746624; 1: waitid() returned 0 si_pid=1073838904; si_uid=-1073746612; si_status=1 si_code=1073838488 (????); si_signo=-1073746624; child 1 PID=28443 finished 1: waitid() returned 0 si_pid=28443; si_uid=500; si_status=0 si_code=1 (CLD_EXITED); si_signo=17; 2: waitid() returned 0 si_pid=28443; si_uid=500; si_status=0 si_code=1 (CLD_EXITED); si_signo=17; child 2 PID=28444 finished 2: waitid() returned 0 si_pid=28444; si_uid=500; si_status=0 si_code=1 (CLD_EXITED); si_signo=17; waitid: No child processes On Solaris 8, the 1st, 2nd, and 4th waitid() calls return si_pid == 0. Cheers, Michael OTHER TESTS (all successful) =========== 1. WSTOPPED tested by sending SIGSTOP to child -- WORKS info.si_signo set to 17 (SIGCHLD) info.so_pid set to PID of child info.si_uid set to UID of child info.si_status set to 0x13 (signalled 19, SIGSTOP) info.si_code set to 5 (CLD_STOPPED) tested by sending SIGTSTP to child -- WORKS info.si_signo set to 17 (SIGCHLD) info.so_pid set to PID of child info.si_uid set to UID of child info.si_status set to 0x14 (signalled 20, SIGTSTP) info.si_code set to 5 (CLD_STOPPED) 2. WCONTINUED -- WORKS info.si_signo set to 17 (SIGCHLD) info.so_pid set to PID of child info.si_uid set to UID of child info.si_status set to 0x12 (signalled 18, SIGCONT) info.si_code set to 6 (CLD_CONTINUED) 3. WEXITED tested termination by signal SIGKILL -- WORKS info.si_signo set to 17 (SIGCHLD) info.so_pid set to PID of child info.si_uid set to UID of child info.si_status set to 0x9 (signalled 9, SIGKILL) info.si_code set to 2 (CLD_KILLED) tested for normal process termination (exit(0)) - WORKS info.si_signo set to 17 (SIGCHLD) info.so_pid set to PID of child info.si_uid set to UID of child info.si_status set to 0x0 (exited, status 0) info.si_code set to 1 (CLD_EXITED) tested for normal process termination (exit(1)) - WORKS info.si_signo set to 17 (SIGCHLD) info.so_pid set to PID of child info.si_uid set to UID of child info.si_status set to 0x1 (exited, status 1) info.si_code set to 1 (CLD_EXITED) 4. Waiting for combinations of WCONTINUED, WEXITED, WSTOPPED: works 5. Waiting for one of WCONTINUED, WEXITED, WSTOPPED while child undergoes a state transition in another category (e.g., waiting for WEXITED and child is stopped by a signal) WORKS (waitid() remains blocked) 6. WNOWAIT -- leaves child in waitable state -- WORKS Tested for WCONTINUED, WEXITED (normal and abnormal termination), and WSTOPPED transitions 7. Create multiple process groups; select of child by process group (idtype == P_PGID) -- WORKS 8. Selection of one child out of several by PID (idtype == P_PID) WORKS 9. Selection of any child (idtype == P_ALL) -- WORKS 10. No child - WORKS (returns errno set to ECHILD) TEXT PROGRAM ============ /* waitid_test.c Michael Kerrisk, Aug 2004 */ #include <sys/types.h> #include <sys/wait.h> #include <time.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #define errMsg(msg) { perror(msg); } #define errExit(msg) { perror(msg); exit(EXIT_FAILURE); } #ifdef __linux__ #include <syscall.h> #define __NR_waitid 284 /* Syscall number on x86 */ _syscall4(int, waitid, idtype_t, __idtype, __id_t, __id, siginfo_t *, __infop, int, __options) #define WSTOPPED WUNTRACED #define WEXITED 0x00000004 #define WCONTINUED 0x00000008 #define WNOWAIT 0x01000000 #endif static void child(int cnum, int nsecs) { printf("child %d PID=%ld started\n", cnum, (long) getpid()); sleep(nsecs); printf("child %d PID=%ld finished\n", cnum, (long) getpid()); } /* child */ int main(int argc, char *argv[]) { siginfo_t info; int options, j, s; char *p; time_t start; start = time(NULL); if (argc < 3) { fprintf(stderr, "%s {escnW} child-secs...\n", argv[0]); exit(EXIT_FAILURE); } options = 0; for (p = argv[1]; *p != '\0'; p++) { if (*p == 'e') options |= WEXITED; else if (*p == 's') options |= WSTOPPED; else if (*p == 'c') options |= WCONTINUED; else if (*p == 'H') options |= WNOHANG; else if (*p == 'W') options |= WNOWAIT; } for (j = 2; j < argc; j++) { switch (fork()) { case -1: errExit("fork"); case 0: child(j - 1, atoi(argv[j])); exit(EXIT_SUCCESS); default: break; } } for (;;) { s = waitid(P_ALL, 0, &info, options); if (s == -1) errExit("waitid"); printf("%3ld: waitid() returned %d\n", (long) (time(NULL) - start), s); printf(" si_pid=%ld; ", (long) info.si_pid); printf("si_uid=%ld; ", (long) info.si_uid); printf("si_status=%ld\n", (long) info.si_status); printf(" si_code=%ld ", (long) info.si_code); printf(" (%s); ", (info.si_code == CLD_EXITED) ? "CLD_EXITED" : (info.si_code == CLD_KILLED) ? "CLD_KILLED" : (info.si_code == CLD_DUMPED) ? "CLD_DUMPED" : (info.si_code == CLD_TRAPPED) ? "CLD_TRAPPED" : (info.si_code == CLD_STOPPED) ? "CLD_STOPPED" : (info.si_code == CLD_CONTINUED) ? "CLD_CONTINUED" : "????" ); printf("si_signo=%ld;\n", (long) info.si_signo); if ((options & WNOHANG) != 0) usleep(500000); /* Just slow things down a little */ } } /* main */ -- NEU: Bis zu 10 GB Speicher für e-mails & Dateien! 1 GB bereits bei GMX FreeMail http://www.gmx.net/de/go/mail ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH] waitid system call 2004-08-19 17:20 ` Michael Kerrisk @ 2004-08-19 20:53 ` Roland McGrath 2004-08-20 6:00 ` Michael Kerrisk 0 siblings, 1 reply; 22+ messages in thread From: Roland McGrath @ 2004-08-19 20:53 UTC (permalink / raw) To: Michael Kerrisk; +Cc: torvalds, akpm, drepper, linux-kernel, michael.kerrisk > I've tested out various things (see below for a summary), and Thanks for testing out the code. I had meant to mention that there is a test program for waitid in the glibc test suite, which is what I used to test the code before submitting it. It's in posix/tst-waitid.c in the glibc CVS sources. You can tweak that program slightly to build it independent of glibc. For anyone who wants to try it out using glibc, I'll attach below the patches that enable use of the system call (if you build glibc against kernel headers including the waitid patch). > all seems well, with one possible doubt. How can one > distinguish "no children to wait for case" and the "child > successfully waited for case" when using WNOHANG? This is something I did consider in detail, though I overlooked commenting on it. The POSIX wording on this is not entirely unambiguous. What it does say is, "If waitid() returns because a child process was found [...], then the structure pointed to by infop shall be filled in by the system [...]" It does not say that *infop is written in any other case. So, I think a POSIX-compliant application must not assume that it will be. Given that specification, I made the system call do just what it says and no more. For a WNOHANG return without a child, it doesn't touch the structure. The tst-waitid program intends to be POSIX-compliant (in its use of waitid), and so I wrote it to zero the si_signo field before the call and check whether it got set to SIGCHLD or not. The POSIX specification for waitid specifically requires that si_signo be set to SIGCHLD when the siginfo_t is filled in. Taking the standard as a whole, you can also conclude that it requires that si_pid be filled in and not zero. So that is also a reasonable test--if you zeroed the structure (or at least the field you want to test) before the waitid call. I think one could even construe the POSIX wording to mean that a WNOHANG return-without-child should not touch the structure at all. However, I would not argue for that and say Solaris should not zero si_pid here. Thanks, Roland glibc patch follows: 2004-08-04 Roland McGrath <roland@redhat.com> * sysdeps/unix/sysv/linux/bits/waitflags.h (WSTOPPED, WEXITED, WCONTINUED, WNOWAIT): New macros. * sysdeps/unix/sysv/linux/waitid.c: New file. Use new syscall when available, or fall back to the waitpid-based generic code. Index: sysdeps/unix/sysv/linux/bits/waitflags.h =================================================================== RCS file: /cvs/glibc/libc/sysdeps/unix/sysv/linux/bits/waitflags.h,v retrieving revision 1.5 diff -p -u -r1.5 waitflags.h --- sysdeps/unix/sysv/linux/bits/waitflags.h 6 Jul 2001 04:56:14 -0000 1.5 +++ sysdeps/unix/sysv/linux/bits/waitflags.h 19 Aug 2004 20:51:17 -0000 @@ -1,5 +1,5 @@ /* Definitions of flag bits for `waitpid' et al. - Copyright (C) 1992, 1996, 1997, 2000 Free Software Foundation, Inc. + Copyright (C) 1992, 1996, 1997, 2000, 2004 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -26,5 +26,11 @@ #define WNOHANG 1 /* Don't block waiting. */ #define WUNTRACED 2 /* Report status of stopped children. */ +/* Bits in the fourth argument to `waitid'. */ +#define WSTOPPED 2 /* Report stopped child (same as WUNTRACED). */ +#define WEXITED 4 /* Report dead child. */ +#define WCONTINUED 8 /* Report continued child. */ +#define WNOWAIT 0x01000000 /* Don't reap, just poll status. */ + #define __WALL 0x40000000 /* Wait for any child. */ #define __WCLONE 0x80000000 /* Wait for cloned process. */ Index: sysdeps/unix/sysv/linux/waitid.c =================================================================== RCS file: sysdeps/unix/sysv/linux/waitid.c diff -N sysdeps/unix/sysv/linux/waitid.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sysdeps/unix/sysv/linux/waitid.c 19 Aug 2004 20:51:17 -0000 @@ -0,0 +1,67 @@ +/* Linux implementation of waitid. + Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sys/wait.h> +#include <kernel-features.h> + +/**** kernel-features.h ****/ +/* Starting with version 2.6.??? the getdents syscall returns d_type + information as well. */ +#if __LINUX_KERNEL_VERSION >= 132615999 +# define __ASSUME_WAITID_SYSCALL 1 +#endif + +#if __ASSUME_WAITID_SYSCALL > 0 + +static inline int +do_waitid (idtype_t idtype, id_t id, siginfo_t *infop, int options) +{ + return INLINE_SYSCALL (waitid, 4, idtype, id, infop, options); +} +# define NO_DO_WAITID + +#elif defined __NR_waitid + +static int do_compat_waitid (idtype_t idtype, id_t id, + siginfo_t *infop, int options); +# define DO_WAITID do_compat_waitid + +static int +do_waitid (idtype_t idtype, id_t id, siginfo_t *infop, int options) +{ + static int waitid_works; + if (waitid_works > 0) + return INLINE_SYSCALL (waitid, 4, idtype, id, infop, options); + if (waitid_works == 0) + { + int result = INLINE_SYSCALL (waitid, 4, idtype, id, infop, options); + if (result < 0 && errno == ENOSYS) + waitid_works = -1; + else + { + waitid_works = 1; + return result; + } + } + return do_compat_waitid (idtype, id, infop, options); +} +#endif + +#include "sysdeps/posix/waitid.c" ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH] waitid system call 2004-08-19 20:53 ` Roland McGrath @ 2004-08-20 6:00 ` Michael Kerrisk 2004-08-20 9:02 ` Michael Kerrisk 0 siblings, 1 reply; 22+ messages in thread From: Michael Kerrisk @ 2004-08-20 6:00 UTC (permalink / raw) To: Roland McGrath; +Cc: torvalds, akpm, drepper, linux-kernel, michael.kerrisk [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #1: Type: text/plain; charset="us-ascii", Size: 2837 bytes --] Roland, > > all seems well, with one possible doubt. How can one > > distinguish "no children to wait for case" and the "child > > successfully waited for case" when using WNOHANG? > > This is something I did consider in detail, though I overlooked > commenting > on it. The POSIX wording on this is not entirely unambiguous. What it > does say is, "If waitid() returns because a child process was found > [...], > then the structure pointed to by infop shall be filled in by the system > [...]" It does not say that *infop is written in any other case. So, I > think a POSIX-compliant application must not assume that it will be. Agreed. But nor does it prohibit it. More below. > Given that specification, I made the system call do just what it says and > no more. For a WNOHANG return without a child, it doesn't touch the > structure. > > The tst-waitid program intends to be POSIX-compliant (in its use of > waitid), and so I wrote it to zero the si_signo field before the call and > check whether it got set to SIGCHLD or not. The POSIX specification for > waitid specifically requires that si_signo be set to SIGCHLD when the > siginfo_t is filled in. Taking the standard as a whole, you can also > conclude that it requires that si_pid be filled in and not zero. So that > is also a reasonable test--if you zeroed the structure (or at least the > field you want to test) before the waitid call. > > I think one could even construe the POSIX wording to mean that a WNOHANG > return-without-child should not touch the structure at all. However, I > would not argue for that and say Solaris should not zero si_pid here. That would certainly strain my powers of interpretation ;-). Anyway, as you noted recently in another thread, sometimes improvements on POSIX are worth having. To that, I'd add: "especially if other systems also have them". I did some more investigaton and testing: -- Tru64 5.1 behaves like Solaris 8 -- si_pid == 0 for the WNOHANG with no children case. -- HP-UX 11 is different -- not even POSIX compliant. It returns -1 with ECHILD in this scenario. -- According to the man pages, waitid() is also present on Irix 6.5 and UnixWare 7, but I don't have access to those systems to run a test (my earlier test program would be sufficient to test on those systems). So, discounting the non-compliant HP-UX, on other implementations we have 2 out of 2 for the "si_pid == 0" behavior. (I will see if I can get access to other systems for further testing.) So, how about reconsidering the approach for Linux? Cheers, Michael PS Perhaps it would be worth investigating this further on the Austin list? I'm happy to start a thread there. -- NEU: Bis zu 10 GB Speicher für e-mails & Dateien! 1 GB bereits bei GMX FreeMail http://www.gmx.net/de/go/mail ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH] waitid system call 2004-08-20 6:00 ` Michael Kerrisk @ 2004-08-20 9:02 ` Michael Kerrisk 2004-08-20 20:04 ` Roland McGrath 2004-08-22 8:53 ` Tonnerre 0 siblings, 2 replies; 22+ messages in thread From: Michael Kerrisk @ 2004-08-20 9:02 UTC (permalink / raw) To: Michael Kerrisk Cc: roland, torvalds, akpm, drepper, linux-kernel, michael.kerrisk [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #1: Type: text/plain; charset="us-ascii", Size: 1269 bytes --] Roland, Just to follow up with one more data point. > I did some more investigaton and testing: > > -- Tru64 5.1 behaves like Solaris 8 -- si_pid == 0 for > the WNOHANG with no children case. > > -- HP-UX 11 is different -- not even POSIX compliant. It > returns -1 with ECHILD in this scenario. > > -- According to the man pages, waitid() is also present on > Irix 6.5 and UnixWare 7, but I don't have access to > those systems to run a test (my earlier test program > would be sufficient to test on those systems). > > So, discounting the non-compliant HP-UX, on other > implementations we have 2 out of 2 for the "si_pid == 0" > behavior. (I will see if I can get access to other > systems for further testing.) So, how about > reconsidering the approach for Linux? Someone has supplied with me with a data point for Irix 6.5 (and 6.2). Irix behaves like Solaris 8. So that's 3 out of 3 for the "si_pid == 0" behavior (plus a buggy HP-UX 11). I will try to get a Unixware data point, but that will probably take several days. (I wonder if anyone can supply an AIX data point?) Cheers, Michael Cheers, Michael -- NEU: Bis zu 10 GB Speicher für e-mails & Dateien! 1 GB bereits bei GMX FreeMail http://www.gmx.net/de/go/mail ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH] waitid system call 2004-08-20 9:02 ` Michael Kerrisk @ 2004-08-20 20:04 ` Roland McGrath 2004-08-24 11:51 ` Michael Kerrisk 2004-08-22 8:53 ` Tonnerre 1 sibling, 1 reply; 22+ messages in thread From: Roland McGrath @ 2004-08-20 20:04 UTC (permalink / raw) To: Michael Kerrisk; +Cc: torvalds, akpm, drepper, linux-kernel, michael.kerrisk Can you give a complete specification of what these other systems do? Do they zero the whole structure? i.e., test by filling with recognizable garbage, and then examine all the fields after the waitid call and tell me what they are. Thanks, Roland ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH] waitid system call 2004-08-20 20:04 ` Roland McGrath @ 2004-08-24 11:51 ` Michael Kerrisk 2004-08-31 6:04 ` Roland McGrath 0 siblings, 1 reply; 22+ messages in thread From: Michael Kerrisk @ 2004-08-24 11:51 UTC (permalink / raw) To: Roland McGrath Cc: torvalds, akpm, drepper, linux-kernel, michael.kerrisk, Tonnerre Roland, > Can you give a complete specification of what these other systems do? > Do they zero the whole structure? i.e., test by filling with > recognizable garbage, and then examine all the fields after the > waitid call and tell me what they are. I've now run a slightly revised version(see below) of my program on a number of platforms. (If anyone can run this program on other Unix implementations supporting waitid(), it would be interesting to see the results posted into this thread. [Tonnerre: I tried contacting you offlist, but did not hear back -- I'd still be interested in the results on AIX, if you care to run the program below, and post the results into this thread. As noted in my other mail, you may need to change a line of the code below: #if ! defined(__hpux) to: #if ! defined(__hpux) && ! defined(_AIX) in order to get the program to compile. ] I added an option that initializes all of the fields to a recognizable garbage value (99), so that one can clearly see if WNOHANG modifies the fields when there are no waitable children. The following table is my attempt to summarise and analyse the results. The actual shell logs of the various runs are shown below. Linux Tru64 Solaris HP-UX Irix 2.6.8.1 5.1 8 11 6.5 +waitid si_pid y. y* y* y y* si_uid y. n* [1] n* [2] n [1] n* si_signo y. y* y* y y* si_status y. y* y* y y# si_code y. y* y* y y* si_errno ?. ?* ?* ? ?* si_stime n. n* y* [3] - n# si_utime n. n* y* [3] - n* Key --- The first character in each table cell indicates whether waitid() sets the field on this platform: y this field is set on this platform n this field is not set on this platform ? there is insufficient information to determine if this field is meaningfully set on this platform - this field is not available on this platform NOTE: The given test does not reveal whether si_errno is meaningfully set on any platform (and I haven't examined the header files sufficiently closely enough to check if any further details can be determined). Offhand, I can't think of any circumstances where it could be meaningful with waitid().) The second character in each table cell indicates (if present) how the field is treated when a WNOHANG operation is performed and there is no child in a waitable state . the field is left unchanged * the field is explicitly initialized to 0 # the field is initialized to some random value (i.e., something I don't understand) NOTE: WNOHANG is broken on HP/UX 11 if there are no children that have yet terminated, waitid() fails with the error ECHILD. Notes to table: [1] On Tru64 5.1 and HP-UX 11, si_uid is not meaningful, but coincides with si_status, so a value is filled in. [2] On Solaris 8, si_uid is not meaningful, but coincides with si_utime, so a value is filled in. [3] On Solaris 8, the si_stime and si_utime fields return values in centiseconds. Summary points -------------- 1. On all implementations (other than Linux), when WNOHANG is specified, all fields of the siginfo_t structure are returned zeroed out if no child is in a waitable state, with the following exceptions: WNOHANG on HP-UX is broken as noted above. On Irix 6.5, si_status and si_stime are filled in with some unexplained values; the remaining fields are zeroed out. 2. All waitpid() implementations support si_pid, si_signo, si_status, and si_code. 3. Only Linux supports si_uid (and the rusage fields, which weren't employed in this test). 4. Solaris is the only implementation that supports si_utime and si_mtime. Actual runs on the various platforms are shown below. Cheers, Michael =========== Linux 2.6.8.1 + waitid patch $ ./a.out escHi 1 3 Linux tekapo 2.6.8.1 #1 Wed Aug 18 11:04:01 CEST 2004 i686 i686 i386 GNU/Linux child 1 PID=8208 started child 2 PID=8209 started 0.04: waitid() returned 0 si_pid=99; si_uid=99; si_signo=99; si_status=99; si_code=99 (????); si_errno=99; si_stime=99; si_utime=99; 0.54: waitid() returned 0 si_pid=99; si_uid=99; si_signo=99; si_status=99; si_code=99 (????); si_errno=99; si_stime=99; si_utime=99; child 1 PID=8208 finished 1.04: waitid() returned 0 si_pid=8208; si_uid=500; si_signo=17; si_status=22; si_code=1 (CLD_EXITED); si_errno=0; si_stime=99; si_utime=99; 1.55: waitid() returned 0 si_pid=99; si_uid=99; si_signo=99; si_status=99; si_code=99 (????); si_errno=99; si_stime=99; si_utime=99; 2.05: waitid() returned 0 si_pid=99; si_uid=99; si_signo=99; si_status=99; si_code=99 (????); si_errno=99; si_stime=99; si_utime=99; 2.55: waitid() returned 0 si_pid=99; si_uid=99; si_signo=99; si_status=99; si_code=99 (????); si_errno=99; si_stime=99; si_utime=99; child 2 PID=8209 finished 3.05: waitid() returned 0 si_pid=8209; si_uid=500; si_signo=17; si_status=22; si_code=1 (CLD_EXITED); si_errno=0; si_stime=99; si_utime=99; 3.55: waitid: No child processes =========== Tru64 5.1 [I have no explanation for the odd si_errno setting on the first call below.] $ ./a.out escHi 1 3 OSF1 spe206.testdrive.hp.com V5.1 2650 alpha child 1 PID=1884812 started 0.01: waitid() returned 0 si_pid=0; si_uid=0; si_signo=0; si_status=0; si_code=0 (????); si_errno=-1024; si_stime=0; si_utime=0; child 2 PID=1885104 started 0.53: waitid() returned 0 si_pid=0; si_uid=0; si_signo=0; si_status=0; si_code=0 (????); si_errno=0; si_stime=0; si_utime=0; child 1 PID=1884812 finished 1.03: waitid() returned 0 si_pid=1884812; si_uid=22; si_signo=20; si_status=22; si_code=1 (CLD_EXITED); si_errno=0; si_stime=0; si_utime=0; 1.53: waitid() returned 0 si_pid=0; si_uid=0; si_signo=0; si_status=0; si_code=0 (????); si_errno=0; si_stime=0; si_utime=0; 2.03: waitid() returned 0 si_pid=0; si_uid=0; si_signo=0; si_status=0; si_code=0 (????); si_errno=0; si_stime=0; si_utime=0; 2.53: waitid() returned 0 si_pid=0; si_uid=0; si_signo=0; si_status=0; si_code=0 (????); si_errno=0; si_stime=0; si_utime=0; child 2 PID=1885104 finished 3.03: waitid() returned 0 si_pid=1885104; si_uid=22; si_signo=20; si_status=22; si_code=1 (CLD_EXITED); si_errno=0; si_stime=0; si_utime=0; 3.54: waitid: No child processes =========== HP-UX 11 [WNOHANG is broken on this platform] $ ./a.out escHi 1 3 HP-UX spe192 B.11.11 U 9000/800 1839940656 unlimited-user license child 2 PID=5729 started child 1 PID=5728 started 0.03: waitid: No child processes $ child 1 PID=5728 finished child 2 PID=5729 finished ./a.out esci 1 3 HP-UX spe192 B.11.11 U 9000/800 1839940656 unlimited-user license child 1 PID=5733 started child 2 PID=5734 started child 1 PID=5733 finished 1.01: waitid() returned 0 si_pid=5733; si_uid=22; si_signo=18; si_status=22; si_code=1 (CLD_EXITED); si_errno=0; child 2 PID=5734 finished 3.01: waitid() returned 0 si_pid=5734; si_uid=22; si_signo=18; si_status=22; si_code=1 (CLD_EXITED); si_errno=0; 3.01: waitid: No child processes =========== Solaris 8 $ ./a.out escHi 1 3 SunOS sunbode6 5.8 Generic_108528-14 sun4u sparc SUNW,Ultra-4 child 1 PID=20682 started 0.02: child 2 PID=20683 started waitid() returned 0 si_pid=0; si_uid=0; si_signo=0; si_status=0; si_code=0 (????); si_errno=0; si_stime=0; si_utime=0; 0.52: waitid() returned 0 si_pid=0; si_uid=0; si_signo=0; si_status=0; si_code=0 (????); si_errno=0; si_stime=0; si_utime=0; child 1 PID=20682 finished 1.03: waitid() returned 0 si_pid=20682; si_uid=80; si_signo=18; si_status=22; si_code=1 (CLD_EXITED); si_errno=0; si_stime=20; si_utime=80; 1.54: waitid() returned 0 si_pid=0; si_uid=0; si_signo=0; si_status=0; si_code=0 (????); si_errno=0; si_stime=0; si_utime=0; 2.05: waitid() returned 0 si_pid=0; si_uid=0; si_signo=0; si_status=0; si_code=0 (????); si_errno=0; si_stime=0; si_utime=0; 2.56: waitid() returned 0 si_pid=0; si_uid=0; si_signo=0; si_status=0; si_code=0 (????); si_errno=0; si_stime=0; si_utime=0; child 2 PID=20683 finished 3.07: waitid() returned 0 si_pid=20683; si_uid=239; si_signo=18; si_status=22; si_code=1 (CLD_EXITED); si_errno=0; si_stime=61; si_utime=239; 3.58: waitid: No child processes =========== Irix 6.5 $ ./a.out escHi 1 3 IRIX64 max 6.5 04091957 IP30 child 1 PID=62684 started child 2 PID=62704 started 0.04: waitid() returned 0 si_pid=0; si_uid=0; si_signo=0; si_status=809598976; si_code=0 (????); si_errno=0; si_stime=-1476395008; si_utime=0; 0.59: waitid() returned 0 si_pid=0; si_uid=0; si_signo=0; si_status=4; si_code=0 (????); si_errno=0; si_stime=-1476395008; si_utime=0; child 1 PID=62684 finished 1.10: waitid() returned 0 si_pid=62684; si_uid=0; si_signo=18; si_status=22; si_code=1 (CLD_EXITED); si_errno=0; si_stime=0; si_utime=0; 1.61: waitid() returned 0 si_pid=0; si_uid=0; si_signo=0; si_status=4; si_code=0 (????); si_errno=0; si_stime=-1476395008; si_utime=0; 2.12: waitid() returned 0 si_pid=0; si_uid=0; si_signo=0; si_status=4; si_code=0 (????); si_errno=0; si_stime=-1476395008; si_utime=0; 2.63: waitid() returned 0 si_pid=0; si_uid=0; si_signo=0; si_status=4; si_code=0 (????); si_errno=0; si_stime=-1476395008; si_utime=0; child 2 PID=62704 finished 3.14: waitid() returned 0 si_pid=62704; si_uid=0; si_signo=18; si_status=22; si_code=1 (CLD_EXITED); si_errno=0; si_stime=0; si_utime=0; 3.65: waitid: No child processes =========== Test program: /* waitid_test.c Michael Kerrisk, Aug 2004 Change history 19 Aug 04 Initial creation 23 Aug 04 Revised/enhanced */ #include <sys/types.h> #include <sys/time.h> #include <sys/wait.h> #include <time.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #define errMsg(msg) { perror(msg); } #define errExit(msg) { perror(msg); exit(EXIT_FAILURE); } #define fatalErr(msg) { fprintf(stderr, "%s\n", msg); \ exit(EXIT_FAILURE); } #ifdef __linux__ #include <syscall.h> #define __NR_waitid 284 /* Syscall number on x86 */ _syscall4(int, waitid, idtype_t, __idtype, __id_t, __id, siginfo_t *, __infop, int, __options) #define WSTOPPED WUNTRACED #define WEXITED 0x00000004 #define WCONTINUED 0x00000008 #define WNOWAIT 0x01000000 #endif #define DUMMY_VAL 99 #if ! defined(__hpux) #define HAVE_TIME_FIELDS #endif /* Consume CPU time for 'nsecs' seconds of *elapsed* time */ static void burnCpu(int nsecs) { struct timeval start, curr; int diff; if (gettimeofday(&start, NULL) == -1) errExit("gettimeofday"); for (;;) { /* gettimeofday() is not a system call on some Unix implementations, so we call getppid() as well, so that both user and system CPU time are consumed */ getppid(); if (gettimeofday(&curr, NULL) == -1) errExit("gettimeofday"); diff = (curr.tv_sec - start.tv_sec) * 1000000 + (curr.tv_usec - start.tv_usec); if (diff >= nsecs * 1000000) break; } } /* burnCpu */ static void child(int cnum, int nsecs) { printf("child %d PID=%ld started\n", cnum, (long) getpid()); burnCpu(nsecs); /* So that values can show up in si_stime and si_utime */ printf("child %d PID=%ld finished\n", cnum, (long) getpid()); } /* child */ int main(int argc, char *argv[]) { siginfo_t info; int options, j, s; char *p; int init, e; struct timeval start, curr; if (gettimeofday(&start, NULL) == -1) errExit("gettimeofday"); if (argc < 3) { fprintf(stderr, "%s {escHWi} child-secs...\n", argv[0]); exit(EXIT_FAILURE); } system("uname -a"); options = 0; init = 0; for (p = argv[1]; *p != '\0'; p++) { if (*p == 'e') options |= WEXITED; else if (*p == 's') options |= WSTOPPED; else if (*p == 'c') options |= WCONTINUED; else if (*p == 'H') options |= WNOHANG; else if (*p == 'W') options |= WNOWAIT; else if (*p == 'i') init = 1; else fatalErr("Bad option letter"); } for (j = 2; j < argc; j++) { switch (fork()) { case -1: errExit("fork"); case 0: child(j - 1, atoi(argv[j])); exit(22); /* Non-zero so it can be clearly distinguished in si_status */ default: break; } } for (;;) { if (init) { info.si_pid = DUMMY_VAL; #ifdef HAVE_TIME_FIELDS info.si_stime = DUMMY_VAL; info.si_utime = DUMMY_VAL; #endif info.si_uid = DUMMY_VAL; info.si_status = DUMMY_VAL; info.si_code = DUMMY_VAL; info.si_signo = DUMMY_VAL; info.si_errno = DUMMY_VAL; } s = waitid(P_ALL, 0, &info, options); e = errno; if (gettimeofday(&curr, NULL) == -1) errExit("gettimeofday"); printf("%0.2f: ", (float) (curr.tv_sec - start.tv_sec) + (float) (curr.tv_usec - start.tv_usec) / 1000000); fflush(NULL); errno = e; if (s == -1) errExit("waitid"); printf("waitid() returned %d\n", s); printf("\t"); printf("si_pid=%ld; ", (long) info.si_pid); printf("si_uid=%ld; ", (long) info.si_uid); printf("si_signo=%ld; ", (long) info.si_signo); printf("\n"); printf("\t"); printf("si_status=%ld; ", (long) info.si_status); printf("si_code=%ld ", (long) info.si_code); printf("(%s); ", (info.si_code == CLD_EXITED) ? "CLD_EXITED" : (info.si_code == CLD_KILLED) ? "CLD_KILLED" : (info.si_code == CLD_DUMPED) ? "CLD_DUMPED" : (info.si_code == CLD_TRAPPED) ? "CLD_TRAPPED" : (info.si_code == CLD_STOPPED) ? "CLD_STOPPED" : (info.si_code == CLD_CONTINUED) ? "CLD_CONTINUED" : "????" ); printf("si_errno=%ld; ", (long) info.si_errno); printf("\n"); #ifdef HAVE_TIME_FIELDS printf("\t"); printf("si_stime=%ld; si_utime=%ld; ", (long) info.si_stime, (long) info.si_utime); printf("\n"); #endif if ((options & WNOHANG) != 0) usleep(500000); /* Just slow things down a little */ } } /* main */ -- NEU: Bis zu 10 GB Speicher für e-mails & Dateien! 1 GB bereits bei GMX FreeMail http://www.gmx.net/de/go/mail ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH] waitid system call 2004-08-24 11:51 ` Michael Kerrisk @ 2004-08-31 6:04 ` Roland McGrath 2004-08-31 6:26 ` Jakub Jelinek 2004-08-31 7:22 ` Michael Kerrisk 0 siblings, 2 replies; 22+ messages in thread From: Roland McGrath @ 2004-08-31 6:04 UTC (permalink / raw) To: Michael Kerrisk Cc: torvalds, akpm, drepper, linux-kernel, michael.kerrisk, Tonnerre The AIX results someone posted suggested that it does not clear siginfo_t fields on WNOHANG early returns. I still maintain that a POSIX application must not assume that waitid will clear any fields. However, since the majority do, I see no harm in making Linux do so as well. Andrew, please throw this on top of the waitid patches. This patch is relative to 2.6.9-rc1-mm1. Thanks, Roland Signed-off-by: Roland McGrath <roland@redhat.com> --- linux-2.6.9-rc1-mm1/kernel/exit.c.~1~ 2004-08-27 13:46:37.000000000 -0700 +++ linux-2.6.9-rc1-mm1/kernel/exit.c 2004-08-30 22:52:54.246036355 -0700 @@ -1369,8 +1369,29 @@ check_continued: end: current->state = TASK_RUNNING; remove_wait_queue(¤t->wait_chldexit,&wait); - if (infop && retval > 0) + if (infop) { + if (retval > 0) retval = 0; + else { + /* + * For a WNOHANG return, clear out all the fields + * we would set so the user can easily tell the + * difference. + */ + if (!retval) + retval = put_user(0, &infop->si_signo); + if (!retval) + retval = put_user(0, &infop->si_errno); + if (!retval) + retval = put_user(0, &infop->si_code); + if (!retval) + retval = put_user(0, &infop->si_pid); + if (!retval) + retval = put_user(0, &infop->si_uid); + if (!retval) + retval = put_user(0, &infop->si_status); + } + } return retval; } ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH] waitid system call 2004-08-31 6:04 ` Roland McGrath @ 2004-08-31 6:26 ` Jakub Jelinek 2004-08-31 6:37 ` Roland McGrath ` (2 more replies) 2004-08-31 7:22 ` Michael Kerrisk 1 sibling, 3 replies; 22+ messages in thread From: Jakub Jelinek @ 2004-08-31 6:26 UTC (permalink / raw) To: Roland McGrath Cc: Michael Kerrisk, torvalds, akpm, drepper, linux-kernel, michael.kerrisk, Tonnerre On Mon, Aug 30, 2004 at 11:04:46PM -0700, Roland McGrath wrote: > + /* > + * For a WNOHANG return, clear out all the fields > + * we would set so the user can easily tell the > + * difference. > + */ > + if (!retval) > + retval = put_user(0, &infop->si_signo); > + if (!retval) > + retval = put_user(0, &infop->si_errno); > + if (!retval) > + retval = put_user(0, &infop->si_code); > + if (!retval) > + retval = put_user(0, &infop->si_pid); > + if (!retval) > + retval = put_user(0, &infop->si_uid); > + if (!retval) > + retval = put_user(0, &infop->si_status); Is it really necessary to check the exit code after each put_user? if (!retval && access_ok(VERIFY_WRITE, infop, sizeof(*infop)))) { retval = __put_user(0, &infop->si_signo); retval |= __put_user(0, &infop->si_errno); retval |= __put_user(0, &infop->si_code); retval |= __put_user(0, &infop->si_pid); retval |= __put_user(0, &infop->si_uid); retval |= __put_user(0, &infop->si_status); } is what kernel usually does when filling multiple structure members. Jakub ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH] waitid system call 2004-08-31 6:26 ` Jakub Jelinek @ 2004-08-31 6:37 ` Roland McGrath 2004-08-31 6:40 ` Andrew Morton 2004-08-31 18:26 ` Linus Torvalds 2 siblings, 0 replies; 22+ messages in thread From: Roland McGrath @ 2004-08-31 6:37 UTC (permalink / raw) To: Jakub Jelinek Cc: Michael Kerrisk, torvalds, akpm, drepper, linux-kernel, michael.kerrisk, Tonnerre > Is it really necessary to check the exit code after each put_user? > if (!retval && access_ok(VERIFY_WRITE, infop, sizeof(*infop)))) { > retval = __put_user(0, &infop->si_signo); > retval |= __put_user(0, &infop->si_errno); > retval |= __put_user(0, &infop->si_code); > retval |= __put_user(0, &infop->si_pid); > retval |= __put_user(0, &infop->si_uid); > retval |= __put_user(0, &infop->si_status); > } > is what kernel usually does when filling multiple structure members. That is certainly fine by me, but shouldn't that be setting retval to -EFAULT if access_ok fails? The waitid patch has a couple of other spots where those several members are filled in and the code uses the several if's. If one should change I suppose they all should. Thanks, Roland ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH] waitid system call 2004-08-31 6:26 ` Jakub Jelinek 2004-08-31 6:37 ` Roland McGrath @ 2004-08-31 6:40 ` Andrew Morton 2004-08-31 15:53 ` Bill Davidsen 2004-08-31 18:26 ` Linus Torvalds 2 siblings, 1 reply; 22+ messages in thread From: Andrew Morton @ 2004-08-31 6:40 UTC (permalink / raw) To: Jakub Jelinek Cc: roland, mtk-lkml, torvalds, drepper, linux-kernel, michael.kerrisk, tonnerre Jakub Jelinek <jakub@redhat.com> wrote: > > On Mon, Aug 30, 2004 at 11:04:46PM -0700, Roland McGrath wrote: > > + /* > > + * For a WNOHANG return, clear out all the fields > > + * we would set so the user can easily tell the > > + * difference. > > + */ > > + if (!retval) > > + retval = put_user(0, &infop->si_signo); > > + if (!retval) > > + retval = put_user(0, &infop->si_errno); > > + if (!retval) > > + retval = put_user(0, &infop->si_code); > > + if (!retval) > > + retval = put_user(0, &infop->si_pid); > > + if (!retval) > > + retval = put_user(0, &infop->si_uid); > > + if (!retval) > > + retval = put_user(0, &infop->si_status); > > Is it really necessary to check the exit code after each put_user? > if (!retval && access_ok(VERIFY_WRITE, infop, sizeof(*infop)))) { > retval = __put_user(0, &infop->si_signo); > retval |= __put_user(0, &infop->si_errno); > retval |= __put_user(0, &infop->si_code); > retval |= __put_user(0, &infop->si_pid); > retval |= __put_user(0, &infop->si_uid); > retval |= __put_user(0, &infop->si_status); > } > is what kernel usually does when filling multiple structure members. I don't think it matters much. Taking seven trips into the fault handler where one would do seems a bit dumb though. ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH] waitid system call 2004-08-31 6:40 ` Andrew Morton @ 2004-08-31 15:53 ` Bill Davidsen 0 siblings, 0 replies; 22+ messages in thread From: Bill Davidsen @ 2004-08-31 15:53 UTC (permalink / raw) To: linux-kernel Andrew Morton wrote: > Jakub Jelinek <jakub@redhat.com> wrote: > >>On Mon, Aug 30, 2004 at 11:04:46PM -0700, Roland McGrath wrote: >> > + /* >> > + * For a WNOHANG return, clear out all the fields >> > + * we would set so the user can easily tell the >> > + * difference. >> > + */ >> > + if (!retval) >> > + retval = put_user(0, &infop->si_signo); >> > + if (!retval) >> > + retval = put_user(0, &infop->si_errno); >> > + if (!retval) >> > + retval = put_user(0, &infop->si_code); >> > + if (!retval) >> > + retval = put_user(0, &infop->si_pid); >> > + if (!retval) >> > + retval = put_user(0, &infop->si_uid); >> > + if (!retval) >> > + retval = put_user(0, &infop->si_status); >> >> Is it really necessary to check the exit code after each put_user? >> if (!retval && access_ok(VERIFY_WRITE, infop, sizeof(*infop)))) { >> retval = __put_user(0, &infop->si_signo); >> retval |= __put_user(0, &infop->si_errno); >> retval |= __put_user(0, &infop->si_code); >> retval |= __put_user(0, &infop->si_pid); >> retval |= __put_user(0, &infop->si_uid); >> retval |= __put_user(0, &infop->si_status); >> } >> is what kernel usually does when filling multiple structure members. > > > I don't think it matters much. Taking seven trips into the fault handler > where one would do seems a bit dumb though. If all you need is good/bad you could just separate the put_user calls with || and only go through the error handler once. -- -bill davidsen (davidsen@tmr.com) "The secret to procrastination is to put things off until the last possible moment - but no longer" -me ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH] waitid system call 2004-08-31 6:26 ` Jakub Jelinek 2004-08-31 6:37 ` Roland McGrath 2004-08-31 6:40 ` Andrew Morton @ 2004-08-31 18:26 ` Linus Torvalds 2004-08-31 23:51 ` Roland McGrath 2 siblings, 1 reply; 22+ messages in thread From: Linus Torvalds @ 2004-08-31 18:26 UTC (permalink / raw) To: Jakub Jelinek Cc: Roland McGrath, Michael Kerrisk, akpm, drepper, linux-kernel, michael.kerrisk, Tonnerre On Tue, 31 Aug 2004, Jakub Jelinek wrote: > > Is it really necessary to check the exit code after each put_user? More importantly, is there really any reason to care at all? There's no real reason to generate extra code to check an error value that is pointless. It should probably just use (void) clear_user(infop, sizeof(*infop)) and be done with it. Linus ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH] waitid system call 2004-08-31 18:26 ` Linus Torvalds @ 2004-08-31 23:51 ` Roland McGrath 2004-09-01 11:31 ` Michael Kerrisk 0 siblings, 1 reply; 22+ messages in thread From: Roland McGrath @ 2004-08-31 23:51 UTC (permalink / raw) To: Linus Torvalds Cc: Jakub Jelinek, Michael Kerrisk, akpm, drepper, linux-kernel, michael.kerrisk, Tonnerre Andrew, please replace waitid-clear-fields.patch with this one. The old log entry is still good. Thanks, Roland --- linux-2.6.9-rc1-mm1/kernel/exit.c.~1~ +++ linux-2.6.9-rc1-mm1/kernel/exit.c @@ -1369,8 +1369,19 @@ check_continued: end: current->state = TASK_RUNNING; remove_wait_queue(¤t->wait_chldexit,&wait); - if (infop && retval > 0) - retval = 0; + if (infop) { + if (retval > 0) + retval = 0; + else if (retval == 0) { + /* + * For a WNOHANG return, clear out all the fields + * we would set so the user can easily tell the + * difference. + */ + if (clear_user(infop, sizeof *infop)) + retval = -EFAULT; + } + } return retval; } ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH] waitid system call 2004-08-31 23:51 ` Roland McGrath @ 2004-09-01 11:31 ` Michael Kerrisk 0 siblings, 0 replies; 22+ messages in thread From: Michael Kerrisk @ 2004-09-01 11:31 UTC (permalink / raw) To: Roland McGrath Cc: torvalds, jakub, akpm, drepper, linux-kernel, michael.kerrisk, tonnerre Just for completeness, I've updated the table below to include the AIX 5.2 result fro Eric Dumazet, and a Unixware result that I've also now got. Unixware is like most other implementations, in zeroing out the siginfo_t structure when WNOHANG has no waitable children. Cheers, Michael Linux Tru64 Solaris HP-UX Irix AIX U/Ware 2.6.8.1 5.1 8 11 6.5 5.2 +waitid si_pid y. y* y* y y* y. y* si_uid y. n* [1] n* [2] n [1] n* n. n* si_signo y. y* y* y y* y. y* si_status y. y* y* y y# y. y* si_code y. y* y* y y* y. y* si_errno ?. ?* ?* ? ?* ?. ?* si_stime n. n* y* [3] - n# - - si_utime n. n* y* [3] - n* - - Key --- The first character in each table cell indicates whether waitid() sets the field on this platform: y this field is set on this platform n this field is not set on this platform ? there is insufficient information to determine if this field is meaningfully set on this platform - this field is not available on this platform NOTE: The given test does not reveal whether si_errno is meaningfully set on any platform (and I haven't examined the header files sufficiently closely enough to check if any further details can be determined). Offhand, I can't think of any circumstances where it could be meaningful with waitid().) The second character in each table cell indicates (if present) how the field is treated when a WNOHANG operation is performed and there is no child in a waitable state . the field is left unchanged * the field is explicitly initialized to 0 NOTE: the Linux behaviour has now changed with the more recent patch that DOES zero out the fields when WNOHANG has no waitable children. # the field is initialized to some random value (i.e., something I don't understand) NOTE: WNOHANG is broken on HP/UX 11 if there are no children that have yet terminated, waitid() fails with the error ECHILD. Notes to table: [1] On Tru64 5.1 and HP-UX 11, si_uid is not meaningful, but coincides with si_status, so a value is filled in. [2] On Solaris 8, si_uid is not meaningful, but coincides with si_utime, so a value is filled in. [3] On Solaris 8, the si_stime and si_utime fields return values in centiseconds. Summary points -------------- 1. On most other implementations (other than AIX), when WNOHANG is specified, all fields of the siginfo_t structure are returned zeroed out if no child is in a waitable state, with the following exceptions: WNOHANG on HP-UX is broken as noted above. On Irix 6.5, si_status and si_stime are filled in with some unexplained values; the remaining fields are zeroed out. 2. All waitpid() implementations support si_pid, si_signo, si_status, and si_code. 3. Only Linux supports si_uid (and the rusage fields, which weren't employed in this test). 4. Solaris is the only implementation that supports si_stime and si_utime. Actual runs on the various platforms are shown below. Cheers, Michael =========== Linux 2.6.8.1 + waitid patch $ ./a.out escHi 1 3 Linux tekapo 2.6.8.1 #1 Wed Aug 18 11:04:01 CEST 2004 i686 i686 i386 GNU/Linux child 1 PID=8208 started child 2 PID=8209 started 0.04: waitid() returned 0 si_pid=99; si_uid=99; si_signo=99; si_status=99; si_code=99 (????); si_errno=99; si_stime=99; si_utime=99; 0.54: waitid() returned 0 si_pid=99; si_uid=99; si_signo=99; si_status=99; si_code=99 (????); si_errno=99; si_stime=99; si_utime=99; child 1 PID=8208 finished 1.04: waitid() returned 0 si_pid=8208; si_uid=500; si_signo=17; si_status=22; si_code=1 (CLD_EXITED); si_errno=0; si_stime=99; si_utime=99; 1.55: waitid() returned 0 si_pid=99; si_uid=99; si_signo=99; si_status=99; si_code=99 (????); si_errno=99; si_stime=99; si_utime=99; 2.05: waitid() returned 0 si_pid=99; si_uid=99; si_signo=99; si_status=99; si_code=99 (????); si_errno=99; si_stime=99; si_utime=99; 2.55: waitid() returned 0 si_pid=99; si_uid=99; si_signo=99; si_status=99; si_code=99 (????); si_errno=99; si_stime=99; si_utime=99; child 2 PID=8209 finished 3.05: waitid() returned 0 si_pid=8209; si_uid=500; si_signo=17; si_status=22; si_code=1 (CLD_EXITED); si_errno=0; si_stime=99; si_utime=99; 3.55: waitid: No child processes =========== Tru64 5.1 [I have no explanation for the odd si_errno setting on the first call below.] $ ./a.out escHi 1 3 OSF1 spe206.testdrive.hp.com V5.1 2650 alpha child 1 PID=1884812 started 0.01: waitid() returned 0 si_pid=0; si_uid=0; si_signo=0; si_status=0; si_code=0 (????); si_errno=-1024; si_stime=0; si_utime=0; child 2 PID=1885104 started 0.53: waitid() returned 0 si_pid=0; si_uid=0; si_signo=0; si_status=0; si_code=0 (????); si_errno=0; si_stime=0; si_utime=0; child 1 PID=1884812 finished 1.03: waitid() returned 0 si_pid=1884812; si_uid=22; si_signo=20; si_status=22; si_code=1 (CLD_EXITED); si_errno=0; si_stime=0; si_utime=0; 1.53: waitid() returned 0 si_pid=0; si_uid=0; si_signo=0; si_status=0; si_code=0 (????); si_errno=0; si_stime=0; si_utime=0; 2.03: waitid() returned 0 si_pid=0; si_uid=0; si_signo=0; si_status=0; si_code=0 (????); si_errno=0; si_stime=0; si_utime=0; 2.53: waitid() returned 0 si_pid=0; si_uid=0; si_signo=0; si_status=0; si_code=0 (????); si_errno=0; si_stime=0; si_utime=0; child 2 PID=1885104 finished 3.03: waitid() returned 0 si_pid=1885104; si_uid=22; si_signo=20; si_status=22; si_code=1 (CLD_EXITED); si_errno=0; si_stime=0; si_utime=0; 3.54: waitid: No child processes =========== HP-UX 11 [WNOHANG is broken on this platform] $ ./a.out escHi 1 3 HP-UX spe192 B.11.11 U 9000/800 1839940656 unlimited-user license child 2 PID=5729 started child 1 PID=5728 started 0.03: waitid: No child processes $ child 1 PID=5728 finished child 2 PID=5729 finished ./a.out esci 1 3 HP-UX spe192 B.11.11 U 9000/800 1839940656 unlimited-user license child 1 PID=5733 started child 2 PID=5734 started child 1 PID=5733 finished 1.01: waitid() returned 0 si_pid=5733; si_uid=22; si_signo=18; si_status=22; si_code=1 (CLD_EXITED); si_errno=0; child 2 PID=5734 finished 3.01: waitid() returned 0 si_pid=5734; si_uid=22; si_signo=18; si_status=22; si_code=1 (CLD_EXITED); si_errno=0; 3.01: waitid: No child processes =========== Solaris 8 $ ./a.out escHi 1 3 SunOS sunbode6 5.8 Generic_108528-14 sun4u sparc SUNW,Ultra-4 child 1 PID=20682 started 0.02: child 2 PID=20683 started waitid() returned 0 si_pid=0; si_uid=0; si_signo=0; si_status=0; si_code=0 (????); si_errno=0; si_stime=0; si_utime=0; 0.52: waitid() returned 0 si_pid=0; si_uid=0; si_signo=0; si_status=0; si_code=0 (????); si_errno=0; si_stime=0; si_utime=0; child 1 PID=20682 finished 1.03: waitid() returned 0 si_pid=20682; si_uid=80; si_signo=18; si_status=22; si_code=1 (CLD_EXITED); si_errno=0; si_stime=20; si_utime=80; 1.54: waitid() returned 0 si_pid=0; si_uid=0; si_signo=0; si_status=0; si_code=0 (????); si_errno=0; si_stime=0; si_utime=0; 2.05: waitid() returned 0 si_pid=0; si_uid=0; si_signo=0; si_status=0; si_code=0 (????); si_errno=0; si_stime=0; si_utime=0; 2.56: waitid() returned 0 si_pid=0; si_uid=0; si_signo=0; si_status=0; si_code=0 (????); si_errno=0; si_stime=0; si_utime=0; child 2 PID=20683 finished 3.07: waitid() returned 0 si_pid=20683; si_uid=239; si_signo=18; si_status=22; si_code=1 (CLD_EXITED); si_errno=0; si_stime=61; si_utime=239; 3.58: waitid: No child processes =========== Irix 6.5 $ ./a.out escHi 1 3 IRIX64 max 6.5 04091957 IP30 child 1 PID=62684 started child 2 PID=62704 started 0.04: waitid() returned 0 si_pid=0; si_uid=0; si_signo=0; si_status=809598976; si_code=0 (????); si_errno=0; si_stime=-1476395008; si_utime=0; 0.59: waitid() returned 0 si_pid=0; si_uid=0; si_signo=0; si_status=4; si_code=0 (????); si_errno=0; si_stime=-1476395008; si_utime=0; child 1 PID=62684 finished 1.10: waitid() returned 0 si_pid=62684; si_uid=0; si_signo=18; si_status=22; si_code=1 (CLD_EXITED); si_errno=0; si_stime=0; si_utime=0; 1.61: waitid() returned 0 si_pid=0; si_uid=0; si_signo=0; si_status=4; si_code=0 (????); si_errno=0; si_stime=-1476395008; si_utime=0; 2.12: waitid() returned 0 si_pid=0; si_uid=0; si_signo=0; si_status=4; si_code=0 (????); si_errno=0; si_stime=-1476395008; si_utime=0; 2.63: waitid() returned 0 si_pid=0; si_uid=0; si_signo=0; si_status=4; si_code=0 (????); si_errno=0; si_stime=-1476395008; si_utime=0; child 2 PID=62704 finished 3.14: waitid() returned 0 si_pid=62704; si_uid=0; si_signo=18; si_status=22; si_code=1 (CLD_EXITED); si_errno=0; si_stime=0; si_utime=0; 3.65: waitid: No child processes =========== AIX 5.2 # ./waitid_test escHi 1 3 AIX aix610p-ref 2 5 005FD96A4C00 child 1 PID=25204 started child 2 PID=26944 started 0.03: waitid() returned 0 si_pid=99; si_uid=99; si_signo=99; si_status=99; si_code=99 (????); si_errno=99; 0.53: waitid() returned 0 si_pid=99; si_uid=99; si_signo=99; si_status=99; si_code=99 (????); si_errno=99; child 1 PID=25204 finished 1.03: waitid() returned 0 si_pid=25204; si_uid=0; si_signo=20; si_status=22; si_code=10 (CLD_EXITED); si_errno=0; 1.53: waitid() returned 0 si_pid=99; si_uid=99; si_signo=99; si_status=99; si_code=99 (????); si_errno=99; 2.03: waitid() returned 0 si_pid=99; si_uid=99; si_signo=99; si_status=99; si_code=99 (????); si_errno=99; 2.53: waitid() returned 0 si_pid=99; si_uid=99; si_signo=99; si_status=99; si_code=99 (????); si_errno=99; child 2 PID=26944 finished 3.03: waitid() returned 0 si_pid=26944; si_uid=0; si_signo=20; si_status=22; si_code=10 (CLD_EXITED); si_errno=0; 3.53: waitid: No child processes === Unixware $ ./a.out escHi 1 3 UNIX_SV shaft 4.2MP 2.1.1 i386 x86at 0.03: waitid() returned 0 si_pid=0; si_uid=0; si_signo=0; si_status=0; si_code=0 (????); si_errno=0; child 2 PID=13756 started child 1 PID=13755 started 0.53: waitid() returned 0 si_pid=0; si_uid=0; si_signo=0; si_status=0; si_code=0 (????); si_errno=0; 1.03: waitid() returned 0 si_pid=0; si_uid=0; si_signo=0; si_status=0; si_code=0 (????); si_errno=0; child 1 PID=13755 finished 1.53: waitid() returned 0 si_pid=13755; si_uid=0; si_signo=18; si_status=22; si_code=1 (CLD_EXITED); si_errno=0; 2.03: waitid() returned 0 si_pid=0; si_uid=0; si_signo=0; si_status=0; si_code=0 (????); si_errno=0; 2.53: waitid() returned 0 si_pid=0; si_uid=0; si_signo=0; si_status=0; si_code=0 (????); si_errno=0; 3.03: waitid() returned 0 si_pid=0; si_uid=0; si_signo=0; si_status=0; si_code=0 (????); si_errno=0; child 2 PID=13756 finished 3.53: waitid() returned 0 si_pid=13756; si_uid=0; si_signo=18; si_status=22; si_code=1 (CLD_EXITED); si_errno=0; 4.03: waitid: No child processes -- Supergünstige DSL-Tarife + WLAN-Router für 0,- EUR* Jetzt zu GMX wechseln und sparen http://www.gmx.net/de/go/dsl ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH] waitid system call 2004-08-31 6:04 ` Roland McGrath 2004-08-31 6:26 ` Jakub Jelinek @ 2004-08-31 7:22 ` Michael Kerrisk 1 sibling, 0 replies; 22+ messages in thread From: Michael Kerrisk @ 2004-08-31 7:22 UTC (permalink / raw) To: Roland McGrath Cc: torvalds, akpm, drepper, linux-kernel, michael.kerrisk, tonnerre [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #1: Type: text/plain; charset="us-ascii", Size: 988 bytes --] Is anyone writing a manual page for this sys call? If not, I will. > The AIX results someone posted suggested that it does not clear siginfo_t > fields on WNOHANG early returns. Yes. > I still maintain that a POSIX application > must not assume that waitid will clear any fields. Despite the fact that I've pushed in the direction of changing this, I do agree: a portable application must handle weird behaviours on AIX and HP-UX. (And I would document this in the man page.) > However, since the > majority do, I see no harm in making Linux do so as well. And I do think this is the right way to go. Perhaps one day the other implementations will do the Right Thing, or POSIX will tighten its spec to require the behavior currently implemented by the majority -- best then that Linux doesn't imitate the "broken" implementations. Cheers, Michael -- Supergünstige DSL-Tarife + WLAN-Router für 0,- EUR* Jetzt zu GMX wechseln und sparen http://www.gmx.net/de/go/dsl ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH] waitid system call 2004-08-20 9:02 ` Michael Kerrisk 2004-08-20 20:04 ` Roland McGrath @ 2004-08-22 8:53 ` Tonnerre 1 sibling, 0 replies; 22+ messages in thread From: Tonnerre @ 2004-08-22 8:53 UTC (permalink / raw) To: Michael Kerrisk Cc: roland, torvalds, akpm, drepper, linux-kernel, michael.kerrisk [-- Attachment #1: Type: text/plain, Size: 480 bytes --] Salut, On Fri, Aug 20, 2004 at 11:02:36AM +0200, Michael Kerrisk wrote: > Someone has supplied with me with a data point for Irix 6.5 > (and 6.2). Irix behaves like Solaris 8. So that's 3 out > of 3 for the "si_pid == 0" behavior (plus a buggy HP-UX 11). > I will try to get a Unixware data point, but that will > probably take several days. (I wonder if anyone can supply > an AIX data point?) If required I can test it on a RS/6000 next week. Tonnerre [-- Attachment #2: Digital signature --] [-- Type: application/pgp-signature, Size: 189 bytes --] ^ permalink raw reply [flat|nested] 22+ messages in thread
[parent not found: <2tCiy-8pK-13@gated-at.bofh.it>]
* Re: [PATCH] waitid system call [not found] <2tCiy-8pK-13@gated-at.bofh.it> @ 2004-08-16 0:03 ` Andi Kleen 2004-08-16 2:10 ` Roland McGrath 0 siblings, 1 reply; 22+ messages in thread From: Andi Kleen @ 2004-08-16 0:03 UTC (permalink / raw) To: Roland McGrath; +Cc: linux-kernel Roland McGrath <roland@redhat.com> writes: Are you sure you converted the new _rusage member properly in the 64->32bit siginfo converter? struct rusage uses long. > +asmlinkage long sys32_waitid(int which, compat_pid_t pid, > + siginfo_t32 __user *uinfo, int options) > +{ > + siginfo_t info; > + long ret; > + mm_segment_t old_fs = get_fs(); > + > + info.si_signo = 0; > + set_fs (KERNEL_DS); > + ret = sys_waitid(which, pid, (siginfo_t __user *) &info, options); > + set_fs (old_fs); Better use compat_alloc_user_space() for this. Otherwise it won't work for UML/x86-64. Also that will make it easier to port to other architectures. + /* 1 if group stopped since last SIGCONT, -1 if SIGCONT since report */ + int stop_state; Can't this be merged into some other field? No need to waste memory unnecessarily. -Andi ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH] waitid system call 2004-08-16 0:03 ` Andi Kleen @ 2004-08-16 2:10 ` Roland McGrath 0 siblings, 0 replies; 22+ messages in thread From: Roland McGrath @ 2004-08-16 2:10 UTC (permalink / raw) To: Andi Kleen; +Cc: linux-kernel > Are you sure you converted the new _rusage member properly > in the 64->32bit siginfo converter? struct rusage uses long. Aha! Indeed I did not. Thanks for pointing that out. > Better use compat_alloc_user_space() for this. Otherwise it won't > work for UML/x86-64. Also that will make it easier to port to other > architectures. I followed the model of sys32_rt_sigtimedwait and various compat_* functions in kernel/compat.c. In fact, nothing in kernel/compat.c uses compat_alloc_user_space--and most things in arch/x86_64/ia32/sys_ia32.c use the direct stack method as well. To address your concerns, I imagine all these places should be changed en masse. > > + /* 1 if group stopped since last SIGCONT, -1 if SIGCONT since report */ > + int stop_state; > > Can't this be merged into some other field? No need to waste memory > unnecessarily. I think it could be merged into group_stop_count. I just didn't really want to perturb all that code for the first go-round. I can make an attempt at that if all the other potential concerns with the patch are ironed out. So far the patch doesn't really touch existing signal code paths much at all, so it's easier to evaluate. Thanks, Roland ^ permalink raw reply [flat|nested] 22+ messages in thread
end of thread, other threads:[~2004-09-01 11:31 UTC | newest]
Thread overview: 22+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-08-15 23:03 [PATCH] waitid system call Roland McGrath
2004-08-16 5:40 ` Roland McGrath
2004-08-16 17:15 ` Michael Kerrisk
2004-08-16 21:12 ` Roland McGrath
2004-08-19 17:20 ` Michael Kerrisk
2004-08-19 20:53 ` Roland McGrath
2004-08-20 6:00 ` Michael Kerrisk
2004-08-20 9:02 ` Michael Kerrisk
2004-08-20 20:04 ` Roland McGrath
2004-08-24 11:51 ` Michael Kerrisk
2004-08-31 6:04 ` Roland McGrath
2004-08-31 6:26 ` Jakub Jelinek
2004-08-31 6:37 ` Roland McGrath
2004-08-31 6:40 ` Andrew Morton
2004-08-31 15:53 ` Bill Davidsen
2004-08-31 18:26 ` Linus Torvalds
2004-08-31 23:51 ` Roland McGrath
2004-09-01 11:31 ` Michael Kerrisk
2004-08-31 7:22 ` Michael Kerrisk
2004-08-22 8:53 ` Tonnerre
[not found] <2tCiy-8pK-13@gated-at.bofh.it>
2004-08-16 0:03 ` Andi Kleen
2004-08-16 2:10 ` Roland McGrath
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox