* [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
[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 ` [PATCH] waitid system call 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
* Re: [PATCH] waitid system call
2004-08-15 23:03 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 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
* 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: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-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
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 --
[not found] <2tCiy-8pK-13@gated-at.bofh.it>
2004-08-16 0:03 ` [PATCH] waitid system call Andi Kleen
2004-08-16 2:10 ` Roland McGrath
2004-08-15 23:03 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
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox