Module Name: src Committed By: christos Date: Sat Apr 2 20:38:40 UTC 2016
Modified Files: src/sys/kern: kern_exit.c src/sys/sys: Makefile pset.h resource.h wait.h Added Files: src/sys/sys: idtype.h Log Message: Add wait6() to be used to implement waitid, mostly from FreeBSD. Create idtypes.h shared by wait.h and pset.h To generate a diff of this commit: cvs rdiff -u -r1.248 -r1.249 src/sys/kern/kern_exit.c cvs rdiff -u -r1.157 -r1.158 src/sys/sys/Makefile cvs rdiff -u -r0 -r1.1 src/sys/sys/idtype.h cvs rdiff -u -r1.4 -r1.5 src/sys/sys/pset.h cvs rdiff -u -r1.33 -r1.34 src/sys/sys/resource.h cvs rdiff -u -r1.27 -r1.28 src/sys/sys/wait.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/kern/kern_exit.c diff -u src/sys/kern/kern_exit.c:1.248 src/sys/kern/kern_exit.c:1.249 --- src/sys/kern/kern_exit.c:1.248 Tue Oct 13 02:47:21 2015 +++ src/sys/kern/kern_exit.c Sat Apr 2 16:38:40 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: kern_exit.c,v 1.248 2015/10/13 06:47:21 pgoyette Exp $ */ +/* $NetBSD: kern_exit.c,v 1.249 2016/04/02 20:38:40 christos Exp $ */ /*- * Copyright (c) 1998, 1999, 2006, 2007, 2008 The NetBSD Foundation, Inc. @@ -67,7 +67,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: kern_exit.c,v 1.248 2015/10/13 06:47:21 pgoyette Exp $"); +__KERNEL_RCSID(0, "$NetBSD: kern_exit.c,v 1.249 2016/04/02 20:38:40 christos Exp $"); #include "opt_ktrace.h" #include "opt_dtrace.h" @@ -118,8 +118,9 @@ int debug_exit = 0; #define DPRINTF(x) #endif -static int find_stopped_child(struct proc *, pid_t, int, struct proc **, int *); -static void proc_free(struct proc *, struct rusage *); +static int find_stopped_child(struct proc *, idtype_t, id_t, int, + struct proc **, int *, struct wrusage *, siginfo_t *); +static void proc_free(struct proc *, struct wrusage *); /* * DTrace SDT provider definitions @@ -645,17 +646,22 @@ retry: KASSERT(p->p_nlwps == 1); } -int -do_sys_wait(int *pid, int *status, int options, struct rusage *ru) +static int +do_sys_waitid(idtype_t idtype, id_t id, int *pid, int *status, int options, + struct wrusage *wru, siginfo_t *si) { proc_t *child; int error; - if (ru != NULL) { - memset(ru, 0, sizeof(*ru)); - } + + if (wru != NULL) + memset(wru, 0, sizeof(*wru)); + if (si != NULL) + memset(si, 0, sizeof(*si)); + mutex_enter(proc_lock); - error = find_stopped_child(curproc, *pid, options, &child, status); + error = find_stopped_child(curproc, idtype, id, options, &child, status, + wru, si); if (child == NULL) { mutex_exit(proc_lock); *pid = 0; @@ -668,7 +674,7 @@ do_sys_wait(int *pid, int *status, int o if (options & WNOWAIT) { mutex_exit(proc_lock); } else { - proc_free(child, ru); + proc_free(child, wru); } } else { /* Child state must have been SSTOP. */ @@ -679,6 +685,37 @@ do_sys_wait(int *pid, int *status, int o } int +do_sys_wait(int *pid, int *status, int options, struct rusage *ru) +{ + idtype_t idtype; + id_t id; + int ret; + struct wrusage wru; + + /* + * Translate the special pid values into the (idtype, pid) + * pair for wait6. The WAIT_MYPGRP case is handled by + * find_stopped_child() on its own. + */ + if (*pid == WAIT_ANY) { + idtype = P_ALL; + id = 0; + } else if (*pid < 0) { + idtype = P_PGID; + id = (id_t)-*pid; + } else { + idtype = P_PID; + id = (id_t)*pid; + } + options |= WEXITED | WTRAPPED; + ret = do_sys_waitid(idtype, id, pid, status, options, ru ? &wru : NULL, + NULL); + if (ru) + *ru = wru.wru_self; + return ret; +} + +int sys___wait450(struct lwp *l, const struct sys___wait450_args *uap, register_t *retval) { @@ -707,6 +744,161 @@ sys___wait450(struct lwp *l, const struc return error; } +int +sys_wait6(struct lwp *l, const struct sys_wait6_args *uap, register_t *retval) +{ + /* { + syscallarg(idtype_t) idtype; + syscallarg(id_t) id; + syscallarg(int *) status; + syscallarg(int) options; + syscallarg(struct wrusage *) wru; + syscallarg(siginfo_t *) si; + } */ + struct wrusage wru, *wrup; + siginfo_t si, *sip; + idtype_t idtype; + int pid; + id_t id; + int error, status; + + idtype = SCARG(uap, idtype); + id = SCARG(uap, id); + + if (SCARG(uap, wru) != NULL) + wrup = &wru; + else + wrup = NULL; + + if (SCARG(uap, info) != NULL) + sip = &si; + else + sip = NULL; + + /* + * We expect all callers of wait6() to know about WEXITED and + * WTRAPPED. + */ + error = do_sys_waitid(idtype, id, &pid, &status, SCARG(uap, options), + wrup, sip); + + if (SCARG(uap, status) != NULL && error == 0) + error = copyout(&status, SCARG(uap, status), sizeof(status)); + if (SCARG(uap, wru) != NULL && error == 0) + error = copyout(&wru, SCARG(uap, wru), sizeof(wru)); + if (SCARG(uap, info) != NULL && error == 0) + error = copyout(&si, SCARG(uap, info), sizeof(si)); + return error; +} + + +static int +match_process(struct proc *pp, struct proc **q, idtype_t idtype, id_t id, + int options, struct wrusage *wrusage, siginfo_t *siginfo) +{ + struct rusage *rup; + struct proc *p = *q; + + mutex_enter(p->p_lock); + switch (idtype) { + case P_ALL: + break; + case P_PID: + if (p->p_pid != (pid_t)id) { + mutex_exit(p->p_lock); + p = *q = proc_find_raw((pid_t)id); + if (p == NULL || p->p_stat == SIDL || p->p_pptr != pp) { + *q = NULL; + return -1; + } + mutex_enter(p->p_lock); + } + break; + case P_PGID: + if (p->p_pgid != (pid_t)id) + goto out; + break; + case P_SID: + if (p->p_session->s_sid != (pid_t)id) + goto out; + break; + case P_UID: + if (kauth_cred_getuid(p->p_cred) != (uid_t)id) + goto out; + break; + case P_GID: + if (kauth_cred_getgid(p->p_cred) != (gid_t)id) + goto out; + break; + case P_CID: + case P_PSETID: + case P_CPUID: + /* XXX: Implement me */ + default: + out: + mutex_exit(p->p_lock); + return 0; + } + + if ((options & WEXITED) == 0 && p->p_stat == SZOMB) + goto out; + + if (siginfo != NULL) { + siginfo->si_errno = 0; + + /* + * SUSv4 requires that the si_signo value is always + * SIGCHLD. Obey it despite the rfork(2) interface + * allows to request other signal for child exit + * notification. + */ + siginfo->si_signo = SIGCHLD; + + /* + * This is still a rough estimate. We will fix the + * cases TRAPPED, STOPPED, and CONTINUED later. + */ + if (WCOREDUMP(p->p_xstat)) { + siginfo->si_code = CLD_DUMPED; + siginfo->si_status = WTERMSIG(p->p_xstat); + } else if (WIFSIGNALED(p->p_xstat)) { + siginfo->si_code = CLD_KILLED; + siginfo->si_status = WTERMSIG(p->p_xstat); + } else { + siginfo->si_code = CLD_EXITED; + siginfo->si_status = WEXITSTATUS(p->p_xstat); + } + + siginfo->si_pid = p->p_pid; + siginfo->si_uid = kauth_cred_getuid(p->p_cred); + + /* + * The si_addr field would be useful additional + * detail, but apparently the PC value may be lost + * when we reach this point. bzero() above sets + * siginfo->si_addr to NULL. + */ + } + + /* + * There should be no reason to limit resources usage info to + * exited processes only. A snapshot about any resources used + * by a stopped process may be exactly what is needed. + */ + if (wrusage != NULL) { + rup = &wrusage->wru_self; + *rup = p->p_stats->p_ru; + calcru(p, &rup->ru_utime, &rup->ru_stime, NULL, NULL); + + rup = &wrusage->wru_children; + *rup = p->p_stats->p_cru; + calcru(p, &rup->ru_utime, &rup->ru_stime, NULL, NULL); + } + + mutex_exit(p->p_lock); + return 1; +} + /* * Scan list of child processes for a child process that has stopped or * exited. Used by sys_wait4 and 'compat' equivalents. @@ -714,42 +906,50 @@ sys___wait450(struct lwp *l, const struc * Must be called with the proc_lock held, and may release while waiting. */ static int -find_stopped_child(struct proc *parent, pid_t pid, int options, - struct proc **child_p, int *status_p) +find_stopped_child(struct proc *parent, idtype_t idtype, id_t id, int options, + struct proc **child_p, int *status_p, struct wrusage *wru, siginfo_t *si) { struct proc *child, *dead; int error; KASSERT(mutex_owned(proc_lock)); - if (options & ~(WUNTRACED|WNOHANG|WALTSIG|WALLSIG) + if (options & ~(WUNTRACED|WNOHANG|WALTSIG|WALLSIG|WTRAPPED|WEXITED| + WNOWAIT|WCONTINUED) && !(options & WOPTSCHECKED)) { *child_p = NULL; return EINVAL; } - if (pid == 0 && !(options & WOPTSCHECKED)) - pid = -parent->p_pgid; + if ((options & (WEXITED|WUNTRACED|WCONTINUED|WTRAPPED)) == 0) { + /* + * We will be unable to find any matching processes, + * because there are no known events to look for. + * Prefer to return error instead of blocking + * indefinitely. + */ + *child_p = NULL; + return EINVAL; + } + + if ((pid_t)id == WAIT_MYPGRP && (idtype == P_PID || idtype == P_PGID)) { + mutex_enter(parent->p_lock); + id = (id_t)parent->p_pgid; + mutex_exit(parent->p_lock); + idtype = P_PGID; + } for (;;) { error = ECHILD; dead = NULL; LIST_FOREACH(child, &parent->p_children, p_sibling) { - if (pid >= 0) { - if (child->p_pid != pid) { - child = proc_find_raw(pid); - if (child == NULL || - child->p_stat == SIDL || - child->p_pptr != parent) { - child = NULL; - break; - } - } - } else if (pid != WAIT_ANY && child->p_pgid != -pid) { - /* Child not in correct pgrp */ + int rv = match_process(parent, &child, idtype, id, + options, wru, si); + if (rv == -1) + break; + if (rv == 0) continue; - } /* * Wait for processes with p_exitsig != SIGCHLD @@ -760,10 +960,6 @@ find_stopped_child(struct proc *parent, if (((options & WALLSIG) == 0) && (options & WALTSIG ? child->p_exitsig == SIGCHLD : P_EXITSIG(child) != SIGCHLD)){ - if (child->p_pid == pid) { - child = NULL; - break; - } continue; } @@ -784,7 +980,8 @@ find_stopped_child(struct proc *parent, } } - if (child->p_stat == SSTOP && + if ((options & WTRAPPED) != 0 && + child->p_stat == SSTOP && child->p_waited == 0 && (child->p_slflag & PSL_TRACED || options & WUNTRACED)) { @@ -792,13 +989,18 @@ find_stopped_child(struct proc *parent, child->p_waited = 1; parent->p_nstopchild--; } + if (si) { + si->si_status = child->p_xstat; + si->si_code = CLD_TRAPPED; + } break; } - if (parent->p_nstopchild == 0 || child->p_pid == pid) { + if (parent->p_nstopchild == 0) { child = NULL; break; } } + /* XXX: WCONTINUED? */ if (child != NULL || error != 0 || ((options & WNOHANG) != 0 && dead == NULL)) { @@ -828,7 +1030,7 @@ find_stopped_child(struct proc *parent, * *ru is returned to the caller, and must be freed by the caller. */ static void -proc_free(struct proc *p, struct rusage *ru) +proc_free(struct proc *p, struct wrusage *wru) { struct proc *parent = p->p_pptr; struct lwp *l; @@ -878,8 +1080,10 @@ proc_free(struct proc *p, struct rusage ruadd(&p->p_stats->p_ru, &l->l_ru); ruadd(&p->p_stats->p_ru, &p->p_stats->p_cru); ruadd(&parent->p_stats->p_cru, &p->p_stats->p_ru); - if (ru != NULL) - *ru = p->p_stats->p_ru; + if (wru != NULL) { + wru->wru_self = p->p_stats->p_ru; + wru->wru_children = p->p_stats->p_cru; + } p->p_xstat = 0; /* Index: src/sys/sys/Makefile diff -u src/sys/sys/Makefile:1.157 src/sys/sys/Makefile:1.158 --- src/sys/sys/Makefile:1.157 Mon Aug 17 02:16:03 2015 +++ src/sys/sys/Makefile Sat Apr 2 16:38:40 2016 @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.157 2015/08/17 06:16:03 knakahara Exp $ +# $NetBSD: Makefile,v 1.158 2016/04/02 20:38:40 christos Exp $ .include <bsd.own.mk> @@ -21,7 +21,8 @@ INCS= acct.h agpio.h aio.h ansi.h aout_m exec_coff.h exec_ecoff.h exec_elf.h exec_script.h extattr.h extent.h \ fcntl.h fd_set.h fdio.h featuretest.h file.h filedesc.h filio.h \ flashio.h float_ieee754.h fstypes.h gcq.h gmon.h gpio.h hash.h \ - ieee754.h intr.h intrio.h inttypes.h ioccom.h ioctl.h ioctl_compat.h iostat.h ipc.h \ + idtype.h ieee754.h intr.h intrio.h inttypes.h ioccom.h ioctl.h \ + ioctl_compat.h iostat.h ipc.h \ joystick.h \ kcore.h kcpuset.h kgdb.h kmem.h ksem.h ksyms.h ktrace.h \ localedef.h lock.h lockf.h lua.h lwp.h lwpctl.h \ Index: src/sys/sys/pset.h diff -u src/sys/sys/pset.h:1.4 src/sys/sys/pset.h:1.5 --- src/sys/sys/pset.h:1.4 Sat Apr 27 17:35:24 2013 +++ src/sys/sys/pset.h Sat Apr 2 16:38:40 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: pset.h,v 1.4 2013/04/27 21:35:24 joerg Exp $ */ +/* $NetBSD: pset.h,v 1.5 2016/04/02 20:38:40 christos Exp $ */ /* * Copyright (c) 2008, Mindaugas Rasiukevicius <rmind at NetBSD org> @@ -32,17 +32,13 @@ #include <sys/cdefs.h> #include <sys/featuretest.h> #include <sys/types.h> +#include <sys/idtype.h> /* Types of processor-sets */ #define PS_NONE 0 #define PS_MYID -1 #define PS_QUERY -2 -/* ID types for processor-set calls */ -#define P_MYID -1 -#define P_PID 1 -#define P_LWPID 2 - /* For compatibility only */ typedef cpuid_t processorid_t; Index: src/sys/sys/resource.h diff -u src/sys/sys/resource.h:1.33 src/sys/sys/resource.h:1.34 --- src/sys/sys/resource.h:1.33 Fri Jun 8 22:31:15 2012 +++ src/sys/sys/resource.h Sat Apr 2 16:38:40 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: resource.h,v 1.33 2012/06/09 02:31:15 christos Exp $ */ +/* $NetBSD: resource.h,v 1.34 2016/04/02 20:38:40 christos Exp $ */ /* * Copyright (c) 1982, 1986, 1993 @@ -75,6 +75,13 @@ struct rusage { #define ru_last ru_nivcsw }; +#ifdef _NETBSD_SOURCE +struct wrusage { + struct rusage wru_self; + struct rusage wru_children; +}; +#endif + /* * Resource limits */ Index: src/sys/sys/wait.h diff -u src/sys/sys/wait.h:1.27 src/sys/sys/wait.h:1.28 --- src/sys/sys/wait.h:1.27 Sat Apr 2 07:18:26 2016 +++ src/sys/sys/wait.h Sat Apr 2 16:38:40 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: wait.h,v 1.27 2016/04/02 11:18:26 christos Exp $ */ +/* $NetBSD: wait.h,v 1.28 2016/04/02 20:38:40 christos Exp $ */ /* * Copyright (c) 1982, 1986, 1989, 1993, 1994 @@ -35,6 +35,8 @@ #define _SYS_WAIT_H_ #include <sys/featuretest.h> +#include <sys/siginfo.h> +#include <sys/idtype.h> /* * This file holds definitions relevent to the wait4 system call @@ -87,6 +89,11 @@ #define WALLSIG 0x00000008 /* wait for processes that exit with any signal, i.e. SIGCHLD and alternates */ +#define WCONTINUED 0x00000010 /* Report a job control continued + process. */ +#define WEXITED 0x00000020 /* Wait for exited processes. */ +#define WTRAPPED 0x00000040 /* Wait for a process to hit a trap or + a breakpoint. */ /* * These are the Linux names of some of the above flags, for compatibility @@ -171,13 +178,16 @@ union wait { __BEGIN_DECLS struct rusage; /* forward declaration */ +struct wrusage; pid_t wait(int *); pid_t waitpid(pid_t, int *, int); +int waitid(idtype_t, id_t, siginfo_t *, int); #if defined(_XOPEN_SOURCE) || defined(_NETBSD_SOURCE) #ifndef __LIBC12_SOURCE__ pid_t wait3(int *, int, struct rusage *) __RENAME(__wait350); pid_t wait4(pid_t, int *, int, struct rusage *) __RENAME(__wait450); +pid_t wait6(idtype_t, id_t, int *, int, struct wrusage *, siginfo_t *); #endif #endif __END_DECLS Added files: Index: src/sys/sys/idtype.h diff -u /dev/null src/sys/sys/idtype.h:1.1 --- /dev/null Sat Apr 2 16:38:40 2016 +++ src/sys/sys/idtype.h Sat Apr 2 16:38:40 2016 @@ -0,0 +1,55 @@ +/* $NetBSD: idtype.h,v 1.1 2016/04/02 20:38:40 christos Exp $ */ + +/*- + * Copyright (c) 2016 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _SYS_IDTYPE_H_ +#define _SYS_IDTYPE_H_ + +/* + * Using the solaris constants, some of them are not applicable to us + */ +#define P_MYID -1 /* Me/my process group */ +#define P_PID 1 /* A process identifier. */ +#define P_PPID 2 /* A parent process identifier. */ +#define P_PGID 3 /* A process group identifier. */ +#define P_SID 4 /* A session identifier. */ +#define P_CID 5 /* A scheduling class identifier. */ +#define P_UID 6 /* A user identifier. */ +#define P_GID 7 /* A group identifier. */ +#define P_ALL 8 /* All processes. */ +#define P_LWPID 10 /* An LWP identifier. */ +#define P_TASKID 11 /* A task identifier. */ +#define P_PROJID 12 /* A project identifier. */ +#define P_POOLID 13 /* A pool identifier. */ +#define P_ZONEID 14 /* A zone identifier. */ +#define P_CTID 15 /* A (process) contract identifier. */ +#define P_CPUID 16 /* CPU identifier. */ +#define P_PSETID 17 /* Processor set identifier. */ + +#endif /* _SYS_IDTYPE_H_ */