Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys Add wait6() to be used to implement waitid, mostly from ...



details:   https://anonhg.NetBSD.org/src/rev/10f9c957b503
branches:  trunk
changeset: 344498:10f9c957b503
user:      christos <christos%NetBSD.org@localhost>
date:      Sat Apr 02 20:38:40 2016 +0000

description:
Add wait6() to be used to implement waitid, mostly from FreeBSD.
Create idtypes.h shared by wait.h and pset.h

diffstat:

 sys/kern/kern_exit.c |  280 ++++++++++++++++++++++++++++++++++++++++++++------
 sys/sys/Makefile     |    5 +-
 sys/sys/idtype.h     |   55 ++++++++++
 sys/sys/pset.h       |    8 +-
 sys/sys/resource.h   |    9 +-
 sys/sys/wait.h       |   12 ++-
 6 files changed, 321 insertions(+), 48 deletions(-)

diffs (truncated from 576 to 300 lines):

diff -r 54c7b32c2062 -r 10f9c957b503 sys/kern/kern_exit.c
--- a/sys/kern/kern_exit.c      Sat Apr 02 16:18:54 2016 +0000
+++ b/sys/kern/kern_exit.c      Sat Apr 02 20:38:40 2016 +0000
@@ -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 @@
 #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 @@
        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 @@
                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 @@
 }
 
 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 @@
        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 @@
  * 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;



Home | Main Index | Thread Index | Old Index