system - Add wait6(), waitid(), and si_pid/si_uid siginfo support
authorMatthew Dillon <dillon@apollo.backplane.com>
Sun, 30 Sep 2018 19:45:14 +0000 (12:45 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Sun, 30 Sep 2018 20:23:34 +0000 (13:23 -0700)
* Add the wait6() system call (header definitions taken from FreeBSD).
  This required rearranging kern_wait() a bit.  In particular, we now
  maintain a hold count of 1 on the process during processing instead
  of releasing the hold count early.

* Add waitid() to libc (waitid.c taken from FreeBSD).

* Adjust manual pages (taken from FreeBSD).

* Add siginfo si_pid and si_uid support.  This basically allows a process
  taking a signal to determine where the signal came from.  The fields
  already existed in siginfo but were not implemented.

  Implemented using a non-queued per-process array of signal numbers.
  The last originator sending any given signal is recorded and passed
  through to userland in the siginfo.

* Fixes the 'lightdm' X display manager.  lightdm relies on si_pid
  support.  In addition, note that avoiding long lightdm related
  latencies and timeouts require a softlink from libmozjs-52.so to
  libmozjs-52.so.0 (must be addressed in dports, not addressed in this
  commit).

Loosely-taken-from: FreeBSD (wait6, waitid support only)
Reviewed-by: swildner
25 files changed:
lib/libc/gen/Makefile.inc
lib/libc/gen/Symbol.map
lib/libc/gen/waitid.c [new file with mode: 0644]
lib/libc/include/namespace.h
lib/libc/include/un-namespace.h
lib/libc/sys/Makefile.inc
lib/libc/sys/Symbol.map
lib/libc/sys/wait.2
sys/kern/init_sysent.c
sys/kern/kern_exit.c
sys/kern/kern_proc.c
sys/kern/kern_sig.c
sys/kern/syscalls.c
sys/kern/syscalls.master
sys/platform/pc64/x86_64/machdep.c
sys/platform/vkernel64/x86_64/cpu_regs.c
sys/sys/kern_syscall.h
sys/sys/procctl.h
sys/sys/resource.h
sys/sys/signalvar.h
sys/sys/syscall.h
sys/sys/syscall.mk
sys/sys/sysproto.h
sys/sys/sysunion.h
sys/sys/wait.h

index cb8511b..eeab50a 100644 (file)
@@ -41,7 +41,7 @@ SRCS+=  _once_stub.c _pthread_stubs.c _rand48.c _spinlock_stub.c \
        ttyname.c ttyslot.c \
        ualarm.c ucontext.c ulimit.c uname.c unvis.c usleep.c utime.c \
        utmp.c utmpx.c \
-       valloc.c vis.c wait.c wait3.c waitpid.c wordexp.c
+       valloc.c vis.c wait.c wait3.c waitpid.c waitid.c wordexp.c
 
 .if ${LIB} != {c_rtld}
 SRCS+= tls.c
index 013305a..0ff282e 100644 (file)
@@ -489,6 +489,7 @@ DF504.0 {
     svis;
     tcsetsid;
     uid_from_user;
+    waitid;
 };
 
 DFprivate_1.0 {
@@ -676,6 +677,7 @@ DFprivate_1.0 {
     __usleep;
     __wait;
     __waitpid;
+    __waitid;
     _creat;
     _err;
     _readdir_unlocked;
@@ -696,5 +698,6 @@ DFprivate_1.0 {
     _usleep;
     _wait;
     _waitpid;
+    _waitid;
     _warn;
 };
diff --git a/lib/libc/gen/waitid.c b/lib/libc/gen/waitid.c
new file mode 100644 (file)
index 0000000..788faf2
--- /dev/null
@@ -0,0 +1,68 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2012 Jukka A. Ukkonen
+ * All rights reserved.
+ *
+ * This software was developed by Jukka Ukkonen for FreeBSD.
+ *
+ * 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <stddef.h>
+#include <string.h>
+#include <signal.h>
+#include <errno.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+
+int __waitid(idtype_t, id_t, siginfo_t *, int);
+
+int
+__waitid(idtype_t idtype, id_t id, siginfo_t *info, int flags)
+{
+       int status;
+       pid_t ret;
+
+       ret = _wait6(idtype, id, &status, flags, NULL, info);
+
+       /*
+        * According to SUSv4, waitid() shall not return a PID when a
+        * process is found, but only 0.  If a process was actually
+        * found, siginfo_t fields si_signo and si_pid will be
+        * non-zero.  In case WNOHANG was set in the flags and no
+        * process was found those fields are set to zero using
+        * memset() below.
+        */
+       if (ret == 0 && info != NULL)
+               memset(info, 0, sizeof(*info));
+       else if (ret > 0)
+               ret = 0;
+       return (ret);
+}
+
+__weak_reference(__waitid, waitid);
+__weak_reference(__waitid, _waitid);
index d40d59a..ad9404d 100644 (file)
 #define                socketpair                      _socketpair
 #define                usleep                          _usleep
 #define                wait4                           _wait4
+#define                wait6                           _wait6
 #define                waitpid                         _waitpid
+#define                waitid                          _waitid
 #define                write                           _write
 #define                writev                          _writev
 
index 7ad87d7..5fda0b2 100644 (file)
 #undef         socketpair
 #undef         usleep
 #undef         wait4
+#undef         wait6
 #undef         waitpid
+#undef         waitid
 #undef         write
 #undef         writev
 
index 6995fda..d32409b 100644 (file)
@@ -237,6 +237,8 @@ MLINKS+=vmm.2 vmm_guest_ctl.2 \
        vmm.2 vmm_guest_sync_addr.2
 MLINKS+=wait.2 wait3.2 \
        wait.2 wait4.2 \
+       wait.2 wait6.2 \
+       wait.2 waitid.2 \
        wait.2 waitpid.2
 MLINKS+=write.2 extpwrite.2 \
        write.2 extpwritev.2 \
index 7cc20d1..38cd27a 100644 (file)
@@ -324,6 +324,10 @@ DF410.0 {
     getcpuclockid;
 };
 
+DF504.0 {
+    wait6;
+};
+
 DFprivate_1.0 {
     __fork;
 
@@ -623,6 +627,7 @@ DFprivate_1.0 {
     __sys_vmspace_pwrite;
     __sys_vquotactl;
     __sys_wait4;
+    __sys_wait6;
     __sys_write;
     __sys_writev;
 
@@ -922,6 +927,7 @@ DFprivate_1.0 {
     _vmspace_pwrite;
     _vquotactl;
     _wait4;
+    _wait6;
     _write;
     _writev;
 };
index 67919f1..d38da3f 100644 (file)
 .\" SUCH DAMAGE.
 .\"
 .\"     @(#)wait.2     8.2 (Berkeley) 4/19/94
-.\" $FreeBSD: src/lib/libc/sys/wait.2,v 1.6.2.6 2001/12/14 18:34:02 ru Exp $
-.\" $DragonFly: src/lib/libc/sys/wait.2,v 1.4 2007/08/30 20:58:35 pavalos Exp $
+.\" $FreeBSD$
 .\"
-.Dd August 30, 2007
+.Dd December 1, 2017
 .Dt WAIT 2
 .Os
 .Sh NAME
 .Nm wait ,
+.Nm waitid ,
 .Nm waitpid ,
+.Nm wait3 ,
 .Nm wait4 ,
-.Nm wait3
-.Nd wait for process termination
+.Nm wait6
+.Nd wait for processes to change status
 .Sh LIBRARY
 .Lb libc
 .Sh SYNOPSIS
 .In sys/wait.h
 .Ft pid_t
 .Fn wait "int *status"
-.In sys/time.h
-.In sys/resource.h
 .Ft pid_t
 .Fn waitpid "pid_t wpid" "int *status" "int options"
+.In signal.h
+.Ft int
+.Fn waitid "idtype_t idtype" "id_t id" "siginfo_t *info" "int options"
+.In sys/time.h
+.In sys/resource.h
 .Ft pid_t
 .Fn wait3 "int *status" "int options" "struct rusage *rusage"
 .Ft pid_t
 .Fn wait4 "pid_t wpid" "int *status" "int options" "struct rusage *rusage"
+.Ft pid_t
+.Fn wait6 "idtype_t idtype" "id_t id" "int *status" "int options" "struct __wrusage *wrusage" "siginfo_t *infop"
 .Sh DESCRIPTION
 The
 .Fn wait
-function suspends execution of its calling process until
+function suspends execution of its calling thread until
 .Fa status
-information is available for a terminated child process,
+information is available for a child process
 or a signal is received.
 On return from a successful
 .Fn wait
 call,
 the
 .Fa status
-area contains termination information about the process that exited
+area contains information about the process that reported a status change
 as defined below.
 .Pp
 The
 .Fn wait4
-call provides a more general interface for programs
-that need to wait for certain child processes,
+and
+.Fn wait6
+system calls provide a more general interface for programs
+that need to wait for specific child processes,
 that need resource utilization statistics accumulated by child processes,
 or that require options.
-The other wait functions are implemented using
-.Fn wait4 .
+The other wait functions are implemented using either
+.Fn wait4
+or
+.Fn wait6 .
+.Pp
+The
+.Fn wait6
+function is the most general function in this family and its distinct
+features are:
+.Pp
+All of the desired process statuses to be waited on must be explicitly
+specified in
+.Fa options .
+The
+.Fn wait ,
+.Fn waitpid ,
+.Fn wait3 ,
+and
+.Fn wait4
+functions all implicitly wait for exited and trapped processes,
+but the
+.Fn waitid
+and
+.Fn wait6
+functions require the corresponding
+.Dv WEXITED
+and
+.Dv WTRAPPED
+flags to be explicitly specified.
+This allows waiting for processes which have experienced other
+status changes without having to also handle the exit status from
+terminated processes.
 .Pp
 The
+.Fn wait6
+function accepts a
+.Fa wrusage
+argument which points to a structure defined as:
+.Bd -literal
+struct __wrusage {
+       struct rusage   wru_self;
+       struct rusage   wru_children;
+};
+.Ed
+.Pp
+This allows the calling process to collect resource usage statistics
+from both its own child process as well as from its grand children.
+When no resource usage statistics are needed this pointer can be
+.Dv NULL .
+.Pp
+The last argument
+.Fa infop
+must be either
+.Dv NULL
+or a pointer to a
+.Fa siginfo_t
+structure.
+If
+.Pf non- Dv NULL ,
+the structure is filled with the same data as for a
+.Dv SIGCHLD
+signal delivered when the process changed state.
+.Pp
+The set of child processes to be queried is specified by the arguments
+.Fa idtype
+and
+.Fa id .
+The separate
+.Fa idtype
+and
+.Fa id
+arguments support many other types of
+identifiers in addition to process IDs and process group IDs.
+.Bl -bullet -offset indent
+.It
+If
+.Fa idtype
+is
+.Dv P_PID ,
+.Fn waitid
+and
+.Fn wait6
+wait for the child process with a process ID equal to
+.Dv (pid_t)id .
+.It
+If
+.Fa idtype
+is
+.Dv P_PGID ,
+.Fn waitid
+and
+.Fn wait6
+wait for the child process with a process group ID equal to
+.Dv (pid_t)id .
+.It
+If
+.Fa idtype
+is
+.Dv P_ALL ,
+.Fn waitid
+and
+.Fn wait6
+wait for any child process and the
+.Dv id
+is ignored.
+.It
+If
+.Fa idtype
+is
+.Dv P_PID
+or
+.Dv P_PGID
+and the
+.Dv id
+is zero,
+.Fn waitid
+and
+.Fn wait6
+wait for any child process in the same process group as the caller.
+.El
+.Pp
+Non-standard identifier types supported by this
+implementation of
+.Fn waitid
+and
+.Fn wait6
+are:
+.Bl -tag -width P_JAILID
+.It Dv P_UID
+Wait for processes whose effective user ID is equal to
+.Dv (uid_t) Fa id .
+.It Dv P_GID
+Wait for processes whose effective group ID is equal to
+.Dv (gid_t) Fa id .
+.It Dv P_SID
+Wait for processes whose session ID is equal to
+.Fa id .
+.\" This is just how sessions work, not sure this needs to be documented here
+If the child process started its own session,
+its session ID will be the same as its process ID.
+Otherwise the session ID of a child process will match the caller's session ID.
+.It Dv P_JAILID
+Waits for processes within a jail whose jail identifier is equal to
+.Fa id .
+.El
+.Pp
+For the
+.Fn waitpid
+and
+.Fn wait4
+functions, the single
 .Fa wpid
-parameter specifies the set of child processes for which to wait.
+argument specifies the set of child processes for which to wait.
+.Bl -bullet -offset indent
+.It
 If
 .Fa wpid
 is -1, the call waits for any child process.
+.It
 If
 .Fa wpid
 is 0,
 the call waits for any child process in the process group of the caller.
+.It
 If
 .Fa wpid
-is greater than zero, the call waits for the process with process id
+is greater than zero, the call waits for the process with process ID
 .Fa wpid .
+.It
 If
 .Fa wpid
-is less than -1, the call waits for any process whose process group id
+is less than -1, the call waits for any process whose process group ID
 equals the absolute value of
 .Fa wpid .
+.El
 .Pp
 The
 .Fa status
-parameter is defined below.  The
-.Fa options
-parameter contains the bitwise OR of any of the following options.
+argument is defined below.
+.Pp
 The
-.Dv WCONTINUED
-option indicates that children of the current process that
-have continued from a job control stop, by receiving a
+.Fa options
+argument contains the bitwise OR of any of the following options.
+.Bl -tag -width WCONTINUED
+.It Dv WCONTINUED
+Report the status of selected processes that
+have continued from a job control stop by receiving a
 .Dv SIGCONT
-signal, should also have their status reported.
-The
-.Dv WNOHANG
-option
-is used to indicate that the call should not block if
-there are no processes that wish to report status.
-If the
-.Dv WUNTRACED
-option is set,
-children of the current process that are stopped
-due to a
+signal.
+.It Dv WNOHANG
+Do not block when
+there are no processes wishing to report status.
+.It Dv WUNTRACED
+Report the status of selected processes which are stopped due to a
 .Dv SIGTTIN , SIGTTOU , SIGTSTP ,
 or
 .Dv SIGSTOP
-signal also have
-their status reported.
+signal.
+.It Dv WSTOPPED
+An alias for
+.Dv WUNTRACED .
+.It Dv WTRAPPED
+Report the status of selected processes which are being traced via
+.Xr ptrace 2
+and have trapped or reached a breakpoint.
+This flag is implicitly set for the functions
+.Fn wait ,
+.Fn waitpid ,
+.Fn wait3 ,
+and
+.Fn wait4 .
+.br
+For the
+.Fn waitid
+and
+.Fn wait6
+functions, the flag has to be explicitly included in
+.Fa options
+if status reports from trapped processes are expected.
+.It Dv WEXITED
+Report the status of selected processes which have terminated.
+This flag is implicitly set for the functions
+.Fn wait ,
+.Fn waitpid ,
+.Fn wait3 ,
+and
+.Fn wait4 .
+.br
+For the
+.Fn waitid
+and
+.Fn wait6
+functions, the flag has to be explicitly included in
+.Fa options
+if status reports from terminated processes are expected.
+.It Dv WNOWAIT
+Keep the process whose status is returned in a waitable state.
+The process may be waited for again after this call completes.
+.El
+.sp
+For the
+.Fn waitid
+and
+.Fn wait6
+functions, at least one of the options
+.Dv WEXITED ,
+.Dv WUNTRACED ,
+.Dv WSTOPPED ,
+.Dv WTRAPPED ,
+or
+.Dv WCONTINUED
+must be specified.
+Otherwise there will be no events for the call to report.
+To avoid hanging indefinitely in such a case these functions
+return -1 with
+.Dv errno
+set to
+.Dv EINVAL .
 .Pp
 If
 .Fa rusage
-is non-zero, a summary of the resources used by the terminated
-process and all its
-children is returned (this information is currently not available
-for stopped processes).
+is non-NULL, a summary of the resources used by the terminated
+process and all its children is returned.
+.Pp
+If
+.Fa wrusage
+is non-NULL, separate summaries are returned for the resources used
+by the terminated process and the resources used by all its children.
+.Pp
+If
+.Fa infop
+is non-NULL, a
+.Dv siginfo_t
+structure is returned with the
+.Fa si_signo
+field set to
+.Dv SIGCHLD
+and the
+.Fa si_pid
+field set to the process ID of the process reporting status.
+For the exited process, the
+.Fa si_status
+field of the
+.Dv siginfo_t
+structure contains the full 32 bit exit status passed to
+.Xr _exit 2 ;
+the
+.Fa status
+argument of other calls only returns 8 lowest bits of the exit status.
+.Pp
+When the
+.Dv WNOHANG
+option is specified and no processes
+wish to report status,
+.Fn waitid
+sets the
+.Fa si_signo
+and
+.Fa si_pid
+fields in
+.Fa infop
+to zero.
+Checking these fields is the only way to know if a status change was reported.
 .Pp
 When the
 .Dv WNOHANG
 option is specified and no processes
 wish to report status,
 .Fn wait4
-returns a
+and
+.Fn wait6
+return a
 process id
 of 0.
 .Pp
 The
+.Fn wait
+call is the same as
+.Fn wait4
+with a
+.Fa wpid
+value of -1,
+with an
+.Fa options
+value of zero,
+and a
+.Fa rusage
+value of
+.Dv NULL .
+The
 .Fn waitpid
-call is identical to
+function is identical to
 .Fn wait4
 with an
 .Fa rusage
-value of zero.
+value of
+.Dv NULL .
 The older
 .Fn wait3
 call is the same as
@@ -154,10 +426,32 @@ call is the same as
 with a
 .Fa wpid
 value of -1.
+The
+.Fn wait4
+function is identical to
+.Fn wait6
+with the flags
+.Dv WEXITED
+and
+.Dv WTRAPPED
+set in
+.Fa options
+and
+.Fa infop
+set to
+.Dv NULL .
 .Pp
-The following macros may be used to test the manner of exit of the process.
-One of the first three macros will evaluate to a non-zero (true) value:
+The following macros may be used to test the current status of the process.
+Exactly one of the following four macros will evaluate to a non-zero
+.Pq true
+value:
 .Bl -tag -width Ds
+.It Fn WIFCONTINUED status
+True if the process has not terminated, and
+has continued after a job control stop.
+This macro can be true only if the wait call specified the
+.Dv WCONTINUED
+option.
 .It Fn WIFEXITED status
 True if the process terminated normally by a call to
 .Xr _exit 2
@@ -177,12 +471,6 @@ or if the child process is being traced (see
 Depending on the values of those macros, the following macros
 produce the remaining status information about the child process:
 .Bl -tag -width Ds
-.It Fn WIFCONTINUED status
-True if the process has not terminated, and
-has continued after a job control stop.
-This macro can be true only if the wait call specified the
-.Dv WCONTINUED
-option).
 .It Fn WEXITSTATUS status
 If
 .Fn WIFEXITED status
@@ -226,25 +514,49 @@ calls are pending,
 the call may be interrupted or restarted when the signal-catching routine
 returns,
 depending on the options in effect for the signal;
-see
-.Xr intro 2 ,
-System call restart.
+see discussion of
+.Dv SA_RESTART
+in
+.Xr sigaction 2 .
+.Pp
+The implementation queues one
+.Dv SIGCHLD
+signal for each child process whose
+status has changed; if
+.Fn wait
+returns because the status of a child process is available, the pending
+SIGCHLD signal associated with the process ID of the child process will
+be discarded.
+Any other pending
+.Dv SIGCHLD
+signals remain pending.
+.Pp
+If
+.Dv SIGCHLD
+is blocked and
+.Fn wait
+returns because the status of a child process is available, the pending
+.Dv SIGCHLD
+signal will be cleared unless another status of the child process
+is available.
 .Sh RETURN VALUES
 If
 .Fn wait
-returns due to a stopped
+returns due to a stopped, continued,
 or terminated child process, the process ID of the child
-is returned to the calling process.  Otherwise, a value of -1
+is returned to the calling process.
+Otherwise, a value of \-1
 is returned and
 .Va errno
 is set to indicate the error.
 .Pp
 If
+.Fn wait6 ,
 .Fn wait4 ,
 .Fn wait3 ,
 or
 .Fn waitpid
-returns due to a stopped
+returns due to a stopped, continued,
 or terminated child process, the process ID of the child
 is returned to the calling process.
 If there are no children not previously awaited,
@@ -255,56 +567,112 @@ set to
 Otherwise, if
 .Dv WNOHANG
 is specified and there are
-no stopped or exited children,
+no stopped, continued or exited children,
 0 is returned.
 If an error is detected or a caught signal aborts the call,
 a value of -1
 is returned and
 .Va errno
 is set to indicate the error.
+.Pp
+If
+.Fn waitid
+returns because one or more processes have a state change to report,
+0 is returned.
+If an error is detected,
+a value of -1
+is returned and
+.Va errno
+is set to indicate the error.
+If
+.Dv WNOHANG
+is specified and there are
+no stopped, continued or exited children,
+0 is returned.
+The
+.Fa si_signo
+and
+.Fa si_pid
+fields of
+.Fa infop
+must be checked against zero to determine if a process reported status.
+.Pp
+.Fn wait
+called with -1 to wait for any child process will ignore a child that is
+referenced by a process descriptor (see
+.Xr pdfork 2 ) .
+Specific processes can still be waited on by specifying the process ID.
 .Sh ERRORS
-.Fn Wait
+The
+.Fn wait
+function
 will fail and return immediately if:
 .Bl -tag -width Er
 .It Bq Er ECHILD
 The calling process has no existing unwaited-for
 child processes.
+.It Bq Er ECHILD
+No status from the terminated child process is available
+because the calling process has asked the system to discard
+such status by ignoring the signal
+.Dv SIGCHLD
+or setting the flag
+.Dv SA_NOCLDWAIT
+for that signal.
 .It Bq Er EFAULT
 The
 .Fa status
 or
 .Fa rusage
-arguments point to an illegal address.
+argument points to an illegal address.
 (May not be detected before exit of a child process.)
 .It Bq Er EINTR
 The call was interrupted by a caught signal,
 or the signal did not have the
 .Dv SA_RESTART
 flag set.
+.It Bq Er EINVAL
+An invalid value was specified for
+.Fa options ,
+or
+.Fa idtype
+and
+.Fa id
+do not specify a valid set of processes.
 .El
 .Sh SEE ALSO
+.Xr _exit 2 ,
 .Xr ptrace 2 ,
 .Xr sigaction 2 ,
-.Xr _exit 2 ,
-.Xr exit 3
+.Xr exit 3 ,
+.Xr siginfo 3
 .Sh STANDARDS
 The
-.Fn wait
+.Fn wait ,
+.Fn waitpid ,
 and
-.Fn waitpid
+.Fn waitid
 functions are defined by POSIX;
-.Fn wait4
+.Fn wait6 ,
+.Fn wait4 ,
 and
 .Fn wait3
 are not specified by POSIX.
 The
 .Fn WCOREDUMP
 macro
-and the ability to restart a pending
-.Fn wait
-call are extensions to the POSIX interface.
+is an extension to the POSIX interface.
+.Pp
+The ability to use the
+.Dv WNOWAIT
+flag with
+.Fn waitpid
+is an extension;
+.Tn POSIX
+only permits this flag with
+.Fn waitid .
 .Sh HISTORY
-A
+The
 .Fn wait
-function call appeared in
-.At v6 .
+function appeared in
+.At v1 .
index 2e77761..6e2342b 100644 (file)
@@ -564,4 +564,5 @@ struct sysent sysent[] = {
        { AS(lwp_getaffinity_args), (sy_call_t *)sys_lwp_getaffinity }, /* 545 = lwp_getaffinity */
        { AS(lwp_create2_args), (sy_call_t *)sys_lwp_create2 }, /* 546 = lwp_create2 */
        { AS(getcpuclockid_args), (sy_call_t *)sys_getcpuclockid },     /* 547 = getcpuclockid */
+       { AS(wait6_args), (sy_call_t *)sys_wait6 },     /* 548 = wait6 */
 };
index fc2a314..110396e 100644 (file)
@@ -568,11 +568,12 @@ exit1(int rv)
        }
 
        /*
-        * Save exit status and final rusage info, adding in child rusage
-        * info and self times.
+        * Save exit status and final rusage info.  We no longer add
+        * child rusage info into self times, wait4() and kern_wait()
+        * handles it in order to properly support wait6().
         */
        calcru_proc(p, &p->p_ru);
-       ruadd(&p->p_ru, &p->p_cru);
+       /*ruadd(&p->p_ru, &p->p_cru); REMOVED */
 
        /*
         * notify interested parties of our demise.
@@ -884,27 +885,92 @@ lwp_dispose(struct lwp *lp)
 int
 sys_wait4(struct wait_args *uap)
 {
-       struct rusage rusage;
-       int error, status;
+       struct __wrusage wrusage;
+       int error;
+       int status;
+       int options;
+       id_t id;
+       idtype_t idtype;
+
+       options = uap->options | WEXITED | WTRAPPED;
+       id = uap->pid;
+
+       if (id == WAIT_ANY) {
+               idtype = P_ALL;
+       } else if (id == WAIT_MYPGRP) {
+               idtype = P_PGID;
+               id = curproc->p_pgid;
+       } else if (id < 0) {
+               idtype = P_PGID;
+               id = -id;
+       } else {
+               idtype = P_PID;
+       }
+
+       error = kern_wait(idtype, id, &status, options, &wrusage,
+                         NULL, &uap->sysmsg_result);
+
+       if (error == 0 && uap->status)
+               error = copyout(&status, uap->status, sizeof(*uap->status));
+       if (error == 0 && uap->rusage) {
+               ruadd(&wrusage.wru_self, &wrusage.wru_children);
+               error = copyout(&wrusage.wru_self, uap->rusage, sizeof(*uap->rusage));
+       }
+       return (error);
+}
+
+int
+sys_wait6(struct wait6_args *uap)
+{
+       struct __wrusage wrusage;
+       struct __siginfo info;
+       struct __siginfo *infop;
+       int error;
+       int status;
+       int options;
+       id_t id;
+       idtype_t idtype;
+
+       /*
+        * NOTE: wait6() requires WEXITED and WTRAPPED to be specified if
+        *       desired.
+        */
+       options = uap->options;
+       idtype = uap->idtype;
+       id = uap->id;
+       infop = uap->info ? &info : NULL;
+
+       switch(idtype) {
+       case P_PID:
+       case P_PGID:
+               if (id == WAIT_MYPGRP) {
+                       idtype = P_PGID;
+                       id = curproc->p_pgid;
+               }
+               break;
+       default:
+               /* let kern_wait deal with the remainder */
+               break;
+       }
 
-       error = kern_wait(uap->pid, (uap->status ? &status : NULL),
-                         uap->options, (uap->rusage ? &rusage : NULL),
-                         &uap->sysmsg_result);
+       error = kern_wait(idtype, id, &status, options,
+                         &wrusage, infop, &uap->sysmsg_result);
 
        if (error == 0 && uap->status)
                error = copyout(&status, uap->status, sizeof(*uap->status));
-       if (error == 0 && uap->rusage)
-               error = copyout(&rusage, uap->rusage, sizeof(*uap->rusage));
+       if (error == 0 && uap->wrusage)
+               error = copyout(&wrusage, uap->wrusage, sizeof(*uap->wrusage));
+       if (error == 0 && uap->info)
+               error = copyout(&info, uap->info, sizeof(*uap->info));
        return (error);
 }
 
 /*
- * wait1()
- *
- * wait_args(int pid, int *status, int options, struct rusage *rusage)
+ * kernel wait*() system call support
  */
 int
-kern_wait(pid_t pid, int *status, int options, struct rusage *rusage, int *res)
+kern_wait(idtype_t idtype, id_t id, int *status, int options,
+         struct __wrusage *wrusage, struct __siginfo *info, int *res)
 {
        struct thread *td = curthread;
        struct lwp *lp;
@@ -916,10 +982,17 @@ kern_wait(pid_t pid, int *status, int options, struct rusage *rusage, int *res)
        int nfound, error;
        long waitgen;
 
-       if (pid == 0)
-               pid = -q->p_pgid;
-       if (options &~ (WUNTRACED|WNOHANG|WCONTINUED|WLINUXCLONE))
+       /*
+        * Must not have extraneous options.  Must have at least one
+        * matchable option.
+        */
+       if (options &~ (WUNTRACED|WNOHANG|WCONTINUED|WLINUXCLONE|WSTOPPED|
+                       WEXITED|WTRAPPED|WNOWAIT)) {
                return (EINVAL);
+       }
+       if ((options & (WEXITED | WUNTRACED | WCONTINUED | WTRAPPED)) == 0) {
+               return (EINVAL);
+       }
 
        /*
         * Protect the q->p_children list
@@ -956,10 +1029,59 @@ loop:
         */
        waitgen = atomic_fetchadd_long(&q->p_waitgen, 0x80000000);
        LIST_FOREACH(p, &q->p_children, p_sibling) {
-               if (pid != WAIT_ANY &&
-                   p->p_pid != pid && p->p_pgid != -pid) {
+               /*
+                * Filter, (p) will be held on fall-through.  Try to optimize
+                * this to avoid the atomic op until we are pretty sure we
+                * want this process.
+                */
+               switch(idtype) {
+               case P_ALL:
+                       PHOLD(p);
+                       break;
+               case P_PID:
+                       if (p->p_pid != (pid_t)id)
+                               continue;
+                       PHOLD(p);
+                       break;
+               case P_PGID:
+                       if (p->p_pgid != (pid_t)id)
+                               continue;
+                       PHOLD(p);
+                       break;
+               case P_SID:
+                       PHOLD(p);
+                       if (p->p_session && p->p_session->s_sid != (pid_t)id) {
+                               PRELE(p);
+                               continue;
+                       }
+                       break;
+               case P_UID:
+                       PHOLD(p);
+                       if (p->p_ucred->cr_uid != (uid_t)id) {
+                               PRELE(p);
+                               continue;
+                       }
+                       break;
+               case P_GID:
+                       PHOLD(p);
+                       if (p->p_ucred->cr_gid != (gid_t)id) {
+                               PRELE(p);
+                               continue;
+                       }
+                       break;
+               case P_JAILID:
+                       PHOLD(p);
+                       if (p->p_ucred->cr_prison &&
+                           p->p_ucred->cr_prison->pr_id != (int)id) {
+                               PRELE(p);
+                               continue;
+                       }
+                       break;
+               default:
+                       /* unsupported filter */
                        continue;
                }
+               /* (p) is held at this point */
 
                /*
                 * This special case handles a kthread spawned by linux_clone
@@ -971,11 +1093,12 @@ loop:
                 */
                if ((p->p_sigparent != SIGCHLD) ^ 
                    ((options & WLINUXCLONE) != 0)) {
+                       PRELE(p);
                        continue;
                }
 
                nfound++;
-               if (p->p_stat == SZOMB) {
+               if (p->p_stat == SZOMB && (options & WEXITED)) {
                        /*
                         * We may go into SZOMB with threads still present.
                         * We must wait for them to exit before we can reap
@@ -983,19 +1106,16 @@ loop:
                         * non-master threads.
                         *
                         * Only this routine can remove a process from
-                        * the zombie list and destroy it, use PACQUIREZOMB()
-                        * to serialize us and loop if it blocks (interlocked
-                        * by the parent's q->p_token).
-                        *
-                        * WARNING!  (p) can be invalid when PHOLDZOMB(p)
-                        *           returns non-zero.  Be sure not to
-                        *           mess with it.
+                        * the zombie list and destroy it.
                         */
-                       if (PHOLDZOMB(p))
+                       if (PHOLDZOMB(p)) {
+                               PRELE(p);
                                goto loop;
+                       }
                        lwkt_gettoken(&p->p_token);
                        if (p->p_pptr != q) {
                                lwkt_reltoken(&p->p_token);
+                               PRELE(p);
                                PRELEZOMB(p);
                                goto loop;
                        }
@@ -1037,31 +1157,53 @@ loop:
                         * put a hold on the process for short periods of
                         * time.
                         */
-                       PRELE(p);
-                       PSTALL(p, "reap3", 0);
+                       PRELE(p);               /* from top of loop */
+                       PSTALL(p, "reap3", 1);  /* 1 ref (for PZOMBHOLD) */
 
                        /* Take care of our return values. */
                        *res = p->p_pid;
 
-                       if (status)
-                               *status = p->p_xstat;
-                       if (rusage)
-                               *rusage = p->p_ru;
+                       *status = p->p_xstat;
+                       wrusage->wru_self = p->p_ru;
+                       wrusage->wru_children = p->p_cru;
+
+                       if (info) {
+                               bzero(info, sizeof(*info));
+                               info->si_errno = 0;
+                               info->si_signo = SIGCHLD;
+                               if (p->p_xstat)
+                                       info->si_code = CLD_KILLED;
+                               else
+                                       info->si_code = CLD_EXITED;
+                               info->si_status = p->p_xstat;
+                               info->si_pid = p->p_pid;
+                               info->si_uid = p->p_ucred->cr_uid;
+                       }
+
+                       /*
+                        * WNOWAIT shortcuts to done here, leaving the
+                        * child on the zombie list.
+                        */
+                       if (options & WNOWAIT) {
+                               lwkt_reltoken(&p->p_token);
+                               PRELEZOMB(p);
+                               error = 0;
+                               goto done;
+                       }
 
                        /*
                         * If we got the child via a ptrace 'attach',
                         * we need to give it back to the old parent.
                         */
                        if (p->p_oppid && (t = pfind(p->p_oppid)) != NULL) {
-                               PHOLD(p);
                                p->p_oppid = 0;
                                proc_reparent(p, t);
                                ksignal(t, SIGCHLD);
                                wakeup((caddr_t)t);
-                               error = 0;
                                PRELE(t);
                                lwkt_reltoken(&p->p_token);
                                PRELEZOMB(p);
+                               error = 0;
                                goto done;
                        }
 
@@ -1078,6 +1220,7 @@ loop:
 
                        p->p_xstat = 0;
                        ruadd(&q->p_cru, &p->p_ru);
+                       ruadd(&q->p_cru, &p->p_cru);
 
                        /*
                         * Decrement the count of procs running with this uid.
@@ -1125,18 +1268,17 @@ loop:
                         *       interactions with (q) (such as
                         *       fork/exec/wait or 'ps').
                         */
-                       PSTALL(p, "reap4", 0);
+                       PSTALL(p, "reap4", 1);
                        lwkt_reltoken(&q->p_token);
                        vmspace_exitfree(p);
                        lwkt_gettoken(&q->p_token);
-                       PSTALL(p, "reap5", 0);
+                       PSTALL(p, "reap5", 1);
 
                        /*
                         * NOTE: We have to officially release ZOMB in order
                         *       to ensure that a racing thread in kern_wait()
                         *       which blocked on ZOMB is woken up.
                         */
-                       PHOLD(p);
                        PRELEZOMB(p);
                        kfree(p->p_uidpcpu, M_SUBPROC);
                        kfree(p, M_PROC);
@@ -1144,10 +1286,14 @@ loop:
                        error = 0;
                        goto done;
                }
+
+               /*
+                * Process has not yet exited
+                */
                if ((p->p_stat == SSTOP || p->p_stat == SCORE) &&
                    (p->p_flags & P_WAITED) == 0 &&
-                   ((p->p_flags & P_TRACED) || (options & WUNTRACED))) {
-                       PHOLD(p);
+                   (((p->p_flags & P_TRACED) && (options & WTRAPPED)) ||
+                    (options & WSTOPPED))) {
                        lwkt_gettoken(&p->p_token);
                        if (p->p_pptr != q) {
                                lwkt_reltoken(&p->p_token);
@@ -1163,21 +1309,31 @@ loop:
                                goto loop;
                        }
 
-                       p->p_flags |= P_WAITED;
+                       /*
+                        * Don't set P_WAITED if WNOWAIT specified, leaving
+                        * the process in a waitable state.
+                        */
+                       if ((options & WNOWAIT) == 0)
+                               p->p_flags |= P_WAITED;
 
                        *res = p->p_pid;
-                       if (status)
-                               *status = W_STOPCODE(p->p_xstat);
+                       *status = W_STOPCODE(p->p_xstat);
                        /* Zero rusage so we get something consistent. */
-                       if (rusage)
-                               bzero(rusage, sizeof(*rusage));
+                       bzero(wrusage, sizeof(*wrusage));
                        error = 0;
+                       if (info) {
+                               bzero(info, sizeof(*info));
+                               if (p->p_flags & P_TRACED)
+                                       info->si_code = CLD_TRAPPED;
+                               else
+                                       info->si_code = CLD_STOPPED;
+                               info->si_status = p->p_xstat;
+                       }
                        lwkt_reltoken(&p->p_token);
                        PRELE(p);
                        goto done;
                }
                if ((options & WCONTINUED) && (p->p_flags & P_CONTINUED)) {
-                       PHOLD(p);
                        lwkt_gettoken(&p->p_token);
                        if (p->p_pptr != q) {
                                lwkt_reltoken(&p->p_token);
@@ -1191,15 +1347,26 @@ loop:
                        }
 
                        *res = p->p_pid;
-                       p->p_flags &= ~P_CONTINUED;
 
-                       if (status)
-                               *status = SIGCONT;
+                       /*
+                        * Don't set P_WAITED if WNOWAIT specified, leaving
+                        * the process in a waitable state.
+                        */
+                       if ((options & WNOWAIT) == 0)
+                               p->p_flags &= ~P_CONTINUED;
+
+                       *status = SIGCONT;
                        error = 0;
+                       if (info) {
+                               bzero(info, sizeof(*info));
+                               info->si_code = CLD_CONTINUED;
+                               info->si_status = p->p_xstat;
+                       }
                        lwkt_reltoken(&p->p_token);
                        PRELE(p);
                        goto done;
                }
+               PRELE(p);
        }
        if (nfound == 0) {
                error = ECHILD;
index e7c0b4b..0d53256 100644 (file)
@@ -344,10 +344,12 @@ prele(struct proc *p)
  * Hold and flag serialized for zombie reaping purposes.
  *
  * This function will fail if it has to block, returning non-zero with
- * neither the flag set or the hold count bumped.  Note that we must block
- * without holding a ref, meaning that the caller must ensure that (p)
- * remains valid through some other interlock (typically on its parent
- * process's p_token).
+ * neither the flag set or the hold count bumped.  Note that (p) may
+ * not be valid in this case if the caller does not have some other
+ * reference on (p).
+ *
+ * This function does not block on other PHOLD()s, only on other
+ * PHOLDZOMB()s.
  *
  * Zero is returned on success.  The hold count will be incremented and
  * the serialization flag acquired.  Note that serialization is only against
@@ -1146,8 +1148,10 @@ proc_move_allproc_zombie(struct proc *p)
  * if someone has a lock on the proces (p_lock).
  *
  * Caller must hold p->p_token.  We are required to wait until p_lock
- * becomes zero before we can manipulate the list, allowing allproc
+ * becomes one before we can manipulate the list, allowing allproc
  * scans to guarantee consistency during a list scan.
+ *
+ * Assumes caller has one ref.
  */
 void
 proc_remove_zombie(struct proc *p)
@@ -1158,9 +1162,9 @@ proc_remove_zombie(struct proc *p)
        n = ALLPROC_HASH(p->p_pid);
        prg = &procglob[n];
 
-       PSTALL(p, "reap2", 0);
+       PSTALL(p, "reap2", 1);
        lwkt_gettoken(&prg->proc_token);
-       PSTALL(p, "reap2a", 0);
+       PSTALL(p, "reap2a", 1);
        LIST_REMOVE(p, p_list);         /* from remove master list */
        LIST_REMOVE(p, p_sibling);      /* and from sibling list */
        p->p_pptr = NULL;
index 77eb662..ff59d8e 100644 (file)
@@ -224,6 +224,31 @@ sig_ffs(sigset_t *set)
        return (0);
 }
 
+/*
+ * Allows us to populate siginfo->si_pid and si_uid in the target process
+ * (p) from the originating thread (td).  This function must work properly
+ * even if a kernel thread is sending the signal.
+ *
+ * NOTE: Signals are not queued, so if multiple signals are received the
+ *      signal handler will only see the most recent pid and uid for any
+ *      given signal number.
+ */
+static __inline void
+sigsetfrompid(thread_t td, struct proc *p, int sig)
+{
+       struct sigacts *sap;
+
+       if ((sap = p->p_sigacts) == NULL)
+               return;
+       if (td->td_proc) {
+               sap->ps_frominfo[sig].pid = td->td_proc->p_pid;
+               sap->ps_frominfo[sig].uid = td->td_ucred->cr_uid;
+       } else {
+               sap->ps_frominfo[sig].pid = 0;
+               sap->ps_frominfo[sig].uid = 0;
+       }
+}
+
 /* 
  * No requirements. 
  */
@@ -1211,6 +1236,7 @@ lwpsignal(struct proc *p, struct lwp *lp, int sig)
                        lwkt_reltoken(&p->p_token);
                        goto not_stopped;
                }
+               sigsetfrompid(curthread, p, sig);
                if (lp) {
                        spin_lock(&lp->lwp_spin);
                        SIGADDSET(lp->lwp_siglist, sig);
@@ -1331,6 +1357,7 @@ active_process:
         * it to.
         */
        if (lp == NULL) {
+               sigsetfrompid(curthread, p, sig);
                KNOTE(&p->p_klist, NOTE_SIGNAL | sig);
                SIGADDSET_ATOMIC(p->p_siglist, sig);
                goto out;
@@ -1360,6 +1387,7 @@ active_process:
                 */
                lwkt_gettoken(&p->p_token);
                if (p->p_flags & P_PPWAIT) {
+                       sigsetfrompid(curthread, p, sig);
                        SIGADDSET_ATOMIC(p->p_siglist, sig);
                        lwkt_reltoken(&p->p_token);
                        goto out;
@@ -1388,6 +1416,7 @@ active_process:
        /*
         * Mark signal pending at this specific thread.
         */
+       sigsetfrompid(curthread, p, sig);
        spin_lock(&lp->lwp_spin);
        SIGADDSET(lp->lwp_siglist, sig);
        spin_unlock(&lp->lwp_spin);
index df9e415..536c766 100644 (file)
@@ -554,4 +554,5 @@ const char *syscallnames[] = {
        "lwp_getaffinity",                      /* 545 = lwp_getaffinity */
        "lwp_create2",                  /* 546 = lwp_create2 */
        "getcpuclockid",                        /* 547 = getcpuclockid */
+       "wait6",                        /* 548 = wait6 */
 };
index f43e56d..cab91b3 100644 (file)
 545    STD     { int lwp_getaffinity(pid_t pid, lwpid_t tid, cpumask_t *mask); }
 546    STD     { int lwp_create2(struct lwp_params *params, const cpumask_t *mask); }
 547    STD     { int getcpuclockid(pid_t pid, lwpid_t lwp_id, clockid_t *clock_id); }
+548    STD     { int wait6(idtype_t idtype, id_t id, int *status, int options, \
+                               struct __wrusage *wrusage, siginfo_t *info); }
index e83ecca..f708d75 100644 (file)
@@ -798,6 +798,8 @@ sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
 
                /* fill siginfo structure */
                sf.sf_si.si_signo = sig;
+               sf.sf_si.si_pid = psp->ps_frominfo[sig].pid;
+               sf.sf_si.si_uid = psp->ps_frominfo[sig].uid;
                sf.sf_si.si_code = code;
                sf.sf_si.si_addr = (void *)regs->tf_addr;
        } else {
index 5a0f324..ccc91ac 100644 (file)
@@ -219,6 +219,8 @@ sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
 
                /* fill siginfo structure */
                sf.sf_si.si_signo = sig;
+               sf.sf_si.si_pid = psp->ps_frominfo[sig].pid;
+               sf.sf_si.si_uid = psp->ps_frominfo[sig].uid;
                sf.sf_si.si_code = code;
                sf.sf_si.si_addr = (void *)regs->tf_addr;
        } else {
index 2439bcf..30651c2 100644 (file)
@@ -33,6 +33,7 @@
 #error "This file should not be included by userland programs."
 #endif
 
+#include <sys/wait.h>
 #include <sys/uio.h>
 
 #define DUP_FIXED      0x1     /* Copy to specific fd even if in use */
@@ -49,6 +50,8 @@ struct nchandle;
 struct nlookupdata;
 struct rlimit;
 struct rusage;
+struct __wrusage;
+struct __siginfo;
 struct sigaction;
 struct sigaltstack;
 struct __sigset;
@@ -82,8 +85,8 @@ int kern_execve(struct nlookupdata *nd, struct image_args *args);
 /*
  * Prototypes for syscalls in kern/kern_exit.c
  */
-int kern_wait(pid_t pid, int *status, int options, struct rusage *rusage,
-       int *res);
+int kern_wait(idtype_t idtype, id_t id, int *status, int options,
+       struct __wrusage *wrusage, struct __siginfo *info, int *res);
 
 /*
  * Prototypes for syscalls in kern/kern_sig.c
index 33f84a6..f136296 100644 (file)
 #include <sys/types.h>
 #endif
 
+#ifndef _IDTYPE_T_DECLARED
+#define _IDTYPE_T_DECLARED
+/* SEE ALSO SYS/WAIT.H */
+
 typedef enum idtype {
        /*
         * These names were mostly lifted from Solaris source code and
@@ -70,6 +74,8 @@ typedef enum idtype {
        P_PSETID                /* Processor set identifier. */
 } idtype_t;                    /* The type of id_t we are using. */
 
+#endif
+
 struct reaper_status {
        uint32_t        flags;
        uint32_t        refs;
index d6f5bd5..61f68aa 100644 (file)
@@ -90,6 +90,13 @@ struct       rusage {
 #define        ru_last         ru_nivcsw
 };
 
+#if __BSD_VISIBLE
+struct __wrusage {
+       struct rusage   wru_self;
+       struct rusage   wru_children;
+};
+#endif
+
 /*
  * Resource limits
  */
index 80d7fb7..f591753 100644 (file)
 struct sigacts {
        sig_t    ps_sigact[_SIG_MAXSIG];        /* disposition of signals */
        sigset_t ps_catchmask[_SIG_MAXSIG];     /* signals to be blocked */
+       struct {
+               int     pid;
+               int     uid;
+       } ps_frominfo[_SIG_MAXSIG];
        sigset_t ps_sigignore;          /* Signals being ignored. */
        sigset_t ps_sigcatch;           /* Signals being caught by user. */
        sigset_t ps_sigonstack;         /* signals to take on sigstack */
index 11b23e4..ad63faf 100644 (file)
 #define        SYS_lwp_getaffinity     545
 #define        SYS_lwp_create2 546
 #define        SYS_getcpuclockid       547
-#define        SYS_MAXSYSCALL  548
+#define        SYS_wait6       548
+#define        SYS_MAXSYSCALL  549
index bf13b67..45dad8e 100644 (file)
@@ -311,4 +311,5 @@ MIASM =  \
        lwp_setaffinity.o \
        lwp_getaffinity.o \
        lwp_create2.o \
-       getcpuclockid.o
+       getcpuclockid.o \
+       wait6.o
index 0cfaa01..bc527a1 100644 (file)
@@ -2356,6 +2356,17 @@ struct   getcpuclockid_args {
        lwpid_t lwp_id; char lwp_id_[PAD_(lwpid_t)];
        clockid_t *     clock_id;       char clock_id_[PAD_(clockid_t *)];
 };
+struct wait6_args {
+#ifdef _KERNEL
+       struct sysmsg sysmsg;
+#endif
+       idtype_t        idtype; char idtype_[PAD_(idtype_t)];
+       id_t    id;     char id_[PAD_(id_t)];
+       int *   status; char status_[PAD_(int *)];
+       int     options;        char options_[PAD_(int)];
+       struct __wrusage *      wrusage;        char wrusage_[PAD_(struct __wrusage *)];
+       siginfo_t *     info;   char info_[PAD_(siginfo_t *)];
+};
 struct olseek_args {
 #ifdef _KERNEL
        struct sysmsg sysmsg;
@@ -2853,6 +2864,7 @@ int       sys_lwp_setaffinity (struct lwp_setaffinity_args *);
 int    sys_lwp_getaffinity (struct lwp_getaffinity_args *);
 int    sys_lwp_create2 (struct lwp_create2_args *);
 int    sys_getcpuclockid (struct getcpuclockid_args *);
+int    sys_wait6 (struct wait6_args *);
 
 #endif /* !_SYS_SYSPROTO_H_ */
 #undef PAD_
index 3120302..aeca3fa 100644 (file)
@@ -319,4 +319,5 @@ union sysunion {
        struct  lwp_getaffinity_args lwp_getaffinity;
        struct  lwp_create2_args lwp_create2;
        struct  getcpuclockid_args getcpuclockid;
+       struct  wait6_args wait6;
 };
index 4c7a13e..ebd7646 100644 (file)
@@ -34,6 +34,7 @@
 #define        _SYS_WAIT_H_
 
 #include <sys/cdefs.h>
+#include <machine/stdint.h>
 
 /*
  * This file holds definitions relevant to the wait4 system call
@@ -51,7 +52,6 @@
 
 #define        _WSTATUS(x)     (_W_INT(x) & 0177)
 #define        _WSTOPPED       0177            /* _WSTATUS if process is stopped */
-#define        WSTOPPED        _WSTOPPED
 #define        WIFSTOPPED(x)   (_WSTATUS(x) == _WSTOPPED)
 #define        WSTOPSIG(x)     (_W_INT(x) >> 8)
 #define        WIFSIGNALED(x)  (_WSTATUS(x) != _WSTOPPED && _WSTATUS(x) != 0)
  * this option is done, it is as though they were still running... nothing
  * about them is returned.
  */
-#define        WNOHANG         1       /* don't hang in wait */
-#define        WUNTRACED       2       /* tell about stopped, untraced children */
-#define        WCONTINUED      4       /* Report a job control continued process. */
+#define        WNOHANG         0x0001  /* don't hang in wait */
+#define        WUNTRACED       0x0002  /* tell about stopped, untraced children */
+#define        WCONTINUED      0x0004  /* Report a job control continued process. */
+#define WSTOPPED       WUNTRACED
+#define WNOWAIT                0x0008
+#define WEXITED                0x0010
+#define WTRAPPED       0x0020
+
 #if __BSD_VISIBLE
 #define        WLINUXCLONE     0x80000000 /* wait for kthread spawned from linux_clone */
 
 #define        WAIT_MYPGRP     0       /* any process in my process group */
 #endif /* __BSD_VISIBLE */
 
+#ifndef _ID_T_DECLARED
+#define _ID_T_DECLARED
+typedef __int64_t      id_t;   /* general id, can hold gid/pid/uid_t */
+#endif
+
+#ifndef _IDTYPE_T_DECLARED
+#define _IDTYPE_T_DECLARED
+
+/* SEE ALSO SYS/PROCCTL.H */
+
+typedef enum idtype {
+       /*
+        * These names were mostly lifted from Solaris source code and
+        * still use Solaris style naming to avoid breaking any
+        * OpenSolaris code which has been ported to FreeBSD.  There
+        * is no clear FreeBSD counterpart for all of the names, but
+        * some have a clear correspondence to FreeBSD entities.
+        *
+        * The numerical values are kept synchronized with the Solaris
+        * values.
+        */
+       P_PID,                  /* A process identifier. */
+       P_PPID,                 /* A parent process identifier. */
+       P_PGID,                 /* A process group identifier. */
+       P_SID,                  /* A session identifier. */
+       P_CID,                  /* A scheduling class identifier. */
+       P_UID,                  /* A user identifier. */
+       P_GID,                  /* A group identifier. */
+       P_ALL,                  /* All processes. */
+       P_LWPID,                /* An LWP identifier. */
+       P_TASKID,               /* A task identifier. */
+       P_PROJID,               /* A project identifier. */
+       P_POOLID,               /* A pool identifier. */
+       P_JAILID,               /* A zone identifier. */
+       P_CTID,                 /* A (process) contract identifier. */
+       P_CPUID,                /* CPU identifier. */
+       P_PSETID                /* Processor set identifier. */
+} idtype_t;                    /* The type of id_t we are using. */
+
+#endif
+
 #if !defined(_KERNEL) || defined(_KERNEL_VIRTUAL)
 #include <sys/stdint.h>
 
@@ -97,16 +143,23 @@ typedef    __pid_t         pid_t;          /* process id */
 #endif
 
 __BEGIN_DECLS
+struct __siginfo;
 pid_t  wait(int *);
 pid_t  waitpid(pid_t, int *, int);
+#if __POSIX_VISIBLE >= 200112
+int    waitid(idtype_t, id_t, struct __siginfo *, int);
+#endif
 #if __BSD_VISIBLE || (__XSI_VISIBLE && __XSI_VISIBLE < 700)
 struct rusage;
+struct __wrusage;
 #endif
 #if __BSD_VISIBLE || (__XSI_VISIBLE && __XSI_VISIBLE < 600)
 pid_t  wait3(int *, int, struct rusage *);
 #endif
 #if __BSD_VISIBLE
 pid_t  wait4(pid_t, int *, int, struct rusage *);
+pid_t  wait6(idtype_t, id_t, int *, int, struct __wrusage *,
+               struct __siginfo *);
 #endif
 __END_DECLS
 #endif