kernel - Add reapctl() system call for managing sub-processes
authorMatthew Dillon <dillon@apollo.backplane.com>
Mon, 10 Nov 2014 04:03:02 +0000 (20:03 -0800)
committerMatthew Dillon <dillon@apollo.backplane.com>
Mon, 10 Nov 2014 04:03:02 +0000 (20:03 -0800)
* Add reapctl().  This system call allows the current process to become
  the designated reaper for all sub-processes that are directly or indirectly
  forked under it, even if they detach.

  Instead of reparenting to init, related sub-processes will reparent to
  up the tree to the nearest process with reaping management enabled.

* The system call can be run by any user.  Multiple processes in the
  running topology can be reap masters for the processes under them,
  include sub-processes being reap-masters for processes under them,
  recursively.

* The system call provides an easy way to ensure that all processes under
  the current process, when it is a reap master, to be killed.  The first
  child pid under management can be queried, killed, waited upon, and the
  service monitor then simply loops until no children remain.

  Normally this information might not be available or require a 'ps' style
  (expensive) run to obtain.  This way it can be done trivially and
  dependably via reapctl().

14 files changed:
lib/libc/sys/Symbol.map
lib/libc/sys/reapctl.2 [new file with mode: 0644]
sys/kern/init_main.c
sys/kern/init_sysent.c
sys/kern/kern_exit.c
sys/kern/kern_fork.c
sys/kern/syscalls.c
sys/kern/syscalls.master
sys/sys/proc.h
sys/sys/reaper.h [new file with mode: 0644]
sys/sys/syscall.h
sys/sys/syscall.mk
sys/sys/sysproto.h
sys/sys/sysunion.h

index 940e6f4..446d73f 100644 (file)
@@ -140,6 +140,7 @@ DF306.0 {
     modstat;
     mount;
     mountctl;
+    reapctl;
     mprotect;
     mq_close;
     mq_getattr;
@@ -437,6 +438,7 @@ DFprivate_1.0 {
     __sys_modstat;
     __sys_mount;
     __sys_mountctl;
+    __sys_reapctl;
     __sys_mprotect;
     __sys_mq_close;
     __sys_mq_getattr;
@@ -719,6 +721,7 @@ DFprivate_1.0 {
     _modstat;
     _mount;
     _mountctl;
+    _reapctl;
     _mprotect;
     _mq_close;
     _mq_getattr;
diff --git a/lib/libc/sys/reapctl.2 b/lib/libc/sys/reapctl.2
new file mode 100644 (file)
index 0000000..ac8940d
--- /dev/null
@@ -0,0 +1,128 @@
+.\"
+.\" Copyright (c) 2014
+.\"    The DragonFly Project.  All rights reserved.
+.\"
+.\" 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.
+.\" 3. Neither the name of The DragonFly Project nor the names of its
+.\"    contributors may be used to endorse or promote products derived
+.\"    from this software without specific, prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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
+.\" COPYRIGHT HOLDERS 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.
+.\"
+.Dd November 9, 2014
+.Dt REAPCTL 2
+.Os
+.Sh NAME
+.Nm reapctl
+.Nd control reaping of sub-processes
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/reaper.h
+.Ft int
+.Fo reapctl
+.Fa "int op"
+.Fa "union reaper_info *data"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn reapctl
+system call allows a process to take-over the reaping task from init for
+any forked sub-process, recursively (for all children thereafter) which
+would otherwise reparent to init.
+This allows a chain of control to be maintained no matter what the
+sub-process does.
+.Pp
+Any process may become a reaper for its sub-processes.
+The feature may also be used recursively, or independently, to
+create reaping domains or sub-domains.
+.Pp
+This call is typically used by service monitoring programs, jails, or
+chroots to ensure that the underlying services cannot get away from under
+the monitor.
+.Sh CONTROL OPERATIONS
+The following operations are defined in
+.In sys/reaper.h :
+.Bl -tag -width indent
+.It Dv REAPER_OP_ACQUIRE
+Become a reaper for all sub-processes forked after the call returns.
+The data argument is ignored and can be NULL.
+.It Dv REAPER_OP_RELEASE
+Release reaping duties, reaping returns to normal operation.
+The data argument is ignored and can be NULL.
+.It Dv REAPER_OP_STATUS
+Request status.
+The supplied data structure is loaded with the current reaper status.
+The data argument may be NULL, which can be used to test whether
+the system call exists or not (assuming you catch ENOSYS).
+See the include file for more information.
+.Pp
+Current status flags, indicating whether reaping is acquired.
+If reaping is acquired additional data will be returned.
+.Pp
+When reaping is acquired, the first running pid under the reaper
+is also loaded into the data structure, or -1 if there are none
+running.
+Callers wishing to destroy all processes under management can
+kill the process in question, waitpid it, and loop until no processes
+remain.
+This is guarenteed to ultimately irradicate everything that was directly
+or indirectly started under the reaper.
+.Pp
+.El
+.Sh RETURN VALUES
+0 is returned upon successful completion.
+Otherwise -1 is returned and
+.Va errno
+is set to indicate the error.
+.Pp
+If a data structure is supplied, data may be read or written to it
+according to the op code.
+Only sufficient data to support the requested operation is read or
+written.
+.Sh ERRORS
+The
+.Fn reapctl
+function will fail when one of the following occurs:
+.Bl -tag -width Er
+.It Bq Er EALREADY
+An attempt to acquire reaping is made but the current
+process has already acquired the feature.
+.It Bq Er ENOTCONN
+An attempt to release reaping is made but the current
+process has not currently acquired the feature.
+.It Bq Er EINVAL
+The operation is not supported.
+.El
+.Sh SEE ALSO
+.Sh HISTORY
+The
+.Fn reapctl
+system call first appeared in
+.Dx 4.0 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Fn reapctl
+system call was written by
+.An Matthew Dillon .
index f09bfdf..ca71e08 100644 (file)
@@ -91,6 +91,7 @@ struct proc proc0;
 struct lwp lwp0;
 struct thread thread0;
 struct sys_kpmap *kpmap;
+struct sysreaper initreaper;
 
 int cmask = CMASK;
 u_int cpu_mi_feature;
@@ -702,6 +703,7 @@ create_init(const void *udata __unused)
        if (error)
                panic("cannot fork init: %d", error);
        initproc->p_flags |= P_SYSTEM;
+       reaper_init(initproc, &initreaper);
        lp = ONLY_LWP_IN_PROC(initproc);
        cpu_set_fork_handler(lp, start_init, NULL);
        crit_exit();
index 0951244..5e974b7 100644 (file)
@@ -572,4 +572,5 @@ struct sysent sysent[] = {
        { AS(lpathconf_args), (sy_call_t *)sys_lpathconf },     /* 533 = lpathconf */
        { AS(vmm_guest_ctl_args), (sy_call_t *)sys_vmm_guest_ctl },     /* 534 = vmm_guest_ctl */
        { AS(vmm_guest_sync_addr_args), (sy_call_t *)sys_vmm_guest_sync_addr }, /* 535 = vmm_guest_sync_addr */
+       { AS(reapctl_args), (sy_call_t *)sys_reapctl }, /* 536 = reapctl */
 };
index a3ce51e..8b6a423 100644 (file)
@@ -268,6 +268,8 @@ exit1(int rv)
        struct lwp *lp = td->td_lwp;
        struct proc *q;
        struct proc *pp;
+       struct proc *reproc;
+       struct sysreaper *reap;
        struct vmspace *vm;
        struct vnode *vtmp;
        struct exitlist *ep;
@@ -491,14 +493,24 @@ exit1(int rv)
        pp = NULL;
 
        /*
-        * Reparent all of this process's children to the init process.
-        * We must hold initproc->p_token in order to mess with
-        * initproc->p_children.  We already hold p->p_token (to remove
-        * the children from our list).
+        * release controlled reaper for exit if we own it and return the
+        * remaining reaper (the one for us), which we will drop after we
+        * are done.
         */
+       reap = reaper_exit(p);
+
+       /*
+        * Reparent all of this process's children to the init process or
+        * to the designated reaper.  We must hold the reaper's p_token in
+        * order to safely mess with p_children.
+        *
+        * We already hold p->p_token (to remove the children from our list).
+        */
+       reproc = NULL;
        q = LIST_FIRST(&p->p_children);
        if (q) {
-               lwkt_gettoken(&initproc->p_token);
+               reproc = reaper_get(reap);
+               lwkt_gettoken(&reproc->p_token);
                while ((q = LIST_FIRST(&p->p_children)) != NULL) {
                        PHOLD(q);
                        lwkt_gettoken(&q->p_token);
@@ -508,8 +520,8 @@ exit1(int rv)
                                continue;
                        }
                        LIST_REMOVE(q, p_sibling);
-                       LIST_INSERT_HEAD(&initproc->p_children, q, p_sibling);
-                       q->p_pptr = initproc;
+                       LIST_INSERT_HEAD(&reproc->p_children, q, p_sibling);
+                       q->p_pptr = reproc;
                        q->p_sigparent = SIGCHLD;
 
                        /*
@@ -523,8 +535,8 @@ exit1(int rv)
                        lwkt_reltoken(&q->p_token);
                        PRELE(q);
                }
-               lwkt_reltoken(&initproc->p_token);
-               wakeup(initproc);
+               lwkt_reltoken(&reproc->p_token);
+               wakeup(reproc);
        }
 
        /*
@@ -541,18 +553,33 @@ exit1(int rv)
 
        /*
         * Notify parent that we're gone.  If parent has the PS_NOCLDWAIT
-        * flag set, or if the handler is set to SIG_IGN, notify process 1
-        * instead (and hope it will handle this situation).
+        * flag set, or if the handler is set to SIG_IGN, notify the reaper
+        * instead (it will handle this situation).
+        *
+        * NOTE: The reaper can still be the parent process.
         *
         * (must reload pp)
         */
        if (p->p_pptr->p_sigacts->ps_flag & (PS_NOCLDWAIT | PS_CLDSIGIGN)) {
-               proc_reparent(p, initproc);
+               if (reproc == NULL)
+                       reproc = reaper_get(reap);
+               proc_reparent(p, reproc);
        }
+       if (reproc)
+               PRELE(reproc);
+       if (reap)
+               reaper_drop(reap);
 
+       /*
+        * Signal (possibly new) parent.
+        */
        pp = p->p_pptr;
        PHOLD(pp);
        if (p->p_sigparent && pp != initproc) {
+               int sig = p->p_sigparent;
+
+               if (sig != SIGUSR1 && sig != SIGCHLD)
+                       sig = SIGCHLD;
                ksignal(pp, p->p_sigparent);
        } else {
                ksignal(pp, SIGCHLD);
index ef8efcf..49f6a7a 100644 (file)
@@ -67,6 +67,7 @@
 #include <sys/dsched.h>
 
 static MALLOC_DEFINE(M_ATFORK, "atfork", "atfork callback");
+static MALLOC_DEFINE(M_REAPER, "reaper", "process reapers");
 
 /*
  * These are the stuctures used to create a callout list for things to do
@@ -384,6 +385,13 @@ fork1(struct lwp *lp1, int flags, struct proc **procp)
        p2->p_lasttid = -1;     /* first tid will be 0 */
        p2->p_stat = SIDL;
 
+       /*
+        * NOTE: Process 0 will not have a reaper, but process 1 (init) and
+        *       all other processes always will.
+        */
+       if ((p2->p_reaper = p1->p_reaper) != NULL)
+               reaper_hold(p2->p_reaper);
+
        RB_INIT(&p2->p_lwp_tree);
        spin_init(&p2->p_spin, "procfork1");
        lwkt_token_init(&p2->p_token, "proc");
@@ -804,3 +812,245 @@ start_forked_proc(struct lwp *lp1, struct proc *p2)
                        tsleep(lp1->lwp_proc, PINTERLOCKED, "ppwait", 0);
        }
 }
+
+/*
+ * reapctl (int op, union reaper *data)
+ */
+int
+sys_reapctl(struct reapctl_args *uap)
+{
+       struct proc *p = curproc;
+       struct proc *p2;
+       struct sysreaper *reap;
+       union reaper_info udata;
+       int error;
+
+       switch(uap->op) {
+       case REAPER_OP_ACQUIRE:
+               lwkt_gettoken(&p->p_token);
+               reap = kmalloc(sizeof(*reap), M_REAPER, M_WAITOK|M_ZERO);
+               if (p->p_reaper == NULL || p->p_reaper->p != p) {
+                       reaper_init(p, reap);
+                       error = 0;
+               } else {
+                       kfree(reap, M_REAPER);
+                       error = EALREADY;
+               }
+               lwkt_reltoken(&p->p_token);
+               break;
+       case REAPER_OP_RELEASE:
+               lwkt_gettoken(&p->p_token);
+release_again:
+               reap = p->p_reaper;
+               KKASSERT(reap != NULL);
+               if (reap->p == p) {
+                       reaper_hold(reap);      /* in case of thread race */
+                       lockmgr(&reap->lock, LK_EXCLUSIVE);
+                       if (reap->p != p) {
+                               lockmgr(&reap->lock, LK_RELEASE);
+                               reaper_drop(reap);
+                               goto release_again;
+                       }
+                       reap->p = NULL;
+                       p->p_reaper = reap->parent;
+                       if (p->p_reaper)
+                               reaper_hold(p->p_reaper);
+                       lockmgr(&reap->lock, LK_RELEASE);
+                       reaper_drop(reap);      /* our ref */
+                       reaper_drop(reap);      /* old p_reaper ref */
+                       error = 0;
+               } else {
+                       error = ENOTCONN;
+               }
+               lwkt_reltoken(&p->p_token);
+               break;
+       case REAPER_OP_STATUS:
+               bzero(&udata, sizeof(udata));
+               lwkt_gettoken_shared(&p->p_token);
+               if ((reap = p->p_reaper) != NULL && reap->p == p) {
+                       udata.status.flags = reap->flags;
+                       udata.status.refs = reap->refs;
+                       p2 = LIST_FIRST(&p->p_children);
+                       udata.status.pid_head = p2 ? p2->p_pid : -1;
+               }
+               lwkt_reltoken(&p->p_token);
+               if (uap->data) {
+                       error = copyout(&udata, uap->data,
+                                       sizeof(udata.status));
+               } else {
+                       error = 0;
+               }
+               break;
+       default:
+               error = EINVAL;
+               break;
+       }
+       return error;
+}
+
+/*
+ * Bump ref on reaper, preventing destruction
+ */
+void
+reaper_hold(struct sysreaper *reap)
+{
+       KKASSERT(reap->refs > 0);
+       refcount_acquire(&reap->refs);
+}
+
+/*
+ * Drop ref on reaper, destroy the structure on the 1->0
+ * transition and loop on the parent.
+ */
+void
+reaper_drop(struct sysreaper *next)
+{
+       struct sysreaper *reap;
+
+       while ((reap = next) != NULL) {
+               if (refcount_release(&reap->refs)) {
+                       next = reap->parent;
+                       KKASSERT(reap->p == NULL);
+                       reap->parent = NULL;
+                       kfree(reap, M_REAPER);
+               } else {
+                       next = NULL;
+               }
+       }
+}
+
+/*
+ * Initialize a static or newly allocated reaper structure
+ */
+void
+reaper_init(struct proc *p, struct sysreaper *reap)
+{
+       reap->parent = p->p_reaper;
+       reap->p = p;
+       if (p == initproc) {
+               reap->flags = REAPER_STAT_OWNED | REAPER_STAT_REALINIT;
+               reap->refs = 2;
+       } else {
+               reap->flags = REAPER_STAT_OWNED;
+               reap->refs = 1;
+       }
+       lockinit(&reap->lock, "subrp", 0, 0);
+       cpu_sfence();
+       p->p_reaper = reap;
+}
+
+/*
+ * Called with p->p_token held during exit.
+ *
+ * This is a bit simpler than RELEASE because there are no threads remaining
+ * to race.  We only release if we own the reaper, the exit code will handle
+ * the final p_reaper release.
+ */
+struct sysreaper *
+reaper_exit(struct proc *p)
+{
+       struct sysreaper *reap;
+
+       /*
+        * Release acquired reaper
+        */
+       if ((reap = p->p_reaper) != NULL && reap->p == p) {
+               lockmgr(&reap->lock, LK_EXCLUSIVE);
+               p->p_reaper = reap->parent;
+               if (p->p_reaper)
+                       reaper_hold(p->p_reaper);
+               reap->p = NULL;
+               lockmgr(&reap->lock, LK_RELEASE);
+               reaper_drop(reap);
+       }
+
+       /*
+        * Return and clear reaper (caller is holding p_token for us)
+        * (reap->p does not equal p).  Caller must drop it.
+        */
+       if ((reap = p->p_reaper) != NULL) {
+               p->p_reaper = NULL;
+       }
+       return reap;
+}
+
+/*
+ * Return a held (PHOLD) process representing the reaper for process (p).
+ * NULL should not normally be returned.  Caller should PRELE() the returned
+ * reaper process when finished.
+ *
+ * Remove dead internal nodes while we are at it.
+ *
+ * Process (p)'s token must be held on call.
+ * The returned process's token is NOT acquired by this routine.
+ */
+struct proc *
+reaper_get(struct sysreaper *reap)
+{
+       struct sysreaper *next;
+       struct proc *reproc;
+
+       if (reap == NULL)
+               return NULL;
+
+       /*
+        * Extra hold for loop
+        */
+       reaper_hold(reap);
+
+       while (reap) {
+               lockmgr(&reap->lock, LK_SHARED);
+               if (reap->p) {
+                       /*
+                        * Probable reaper
+                        */
+                       if (reap->p) {
+                               reproc = reap->p;
+                               PHOLD(reproc);
+                               lockmgr(&reap->lock, LK_RELEASE);
+                               reaper_drop(reap);
+                               return reproc;
+                       }
+
+                       /*
+                        * Raced, try again
+                        */
+                       lockmgr(&reap->lock, LK_RELEASE);
+                       continue;
+               }
+
+               /*
+                * Traverse upwards in the reaper topology, destroy
+                * dead internal nodes when possible.
+                *
+                * NOTE: Our ref on next means that a dead node should
+                *       have 2 (ours and reap->parent's).
+                */
+               next = reap->parent;
+               while (next) {
+                       reaper_hold(next);
+                       if (next->refs == 2 && next->p == NULL) {
+                               lockmgr(&reap->lock, LK_RELEASE);
+                               lockmgr(&reap->lock, LK_EXCLUSIVE);
+                               if (next->refs == 2 &&
+                                   reap->parent == next &&
+                                   next->p == NULL) {
+                                       /*
+                                        * reap->parent inherits ref from next.
+                                        */
+                                       reap->parent = next->parent;
+                                       next->parent = NULL;
+                                       reaper_drop(next);      /* ours */
+                                       reaper_drop(next);      /* old parent */
+                                       next = reap->parent;
+                                       continue;       /* possible chain */
+                               }
+                       }
+                       break;
+               }
+               lockmgr(&reap->lock, LK_RELEASE);
+               reaper_drop(reap);
+               reap = next;
+       }
+       return NULL;
+}
index 62ad164..54849f0 100644 (file)
@@ -544,4 +544,5 @@ const char *syscallnames[] = {
        "lpathconf",                    /* 533 = lpathconf */
        "vmm_guest_ctl",                        /* 534 = vmm_guest_ctl */
        "vmm_guest_sync_addr",                  /* 535 = vmm_guest_sync_addr */
+       "reapctl",                      /* 536 = reapctl */
 };
index 141056e..560ad79 100644 (file)
 533    STD     { int lpathconf(char *path, int name); }
 534    STD     { int vmm_guest_ctl(int op, struct vmm_guest_options *options); }
 535    STD     { int vmm_guest_sync_addr(long *dstaddr, long *srcaddr); }
+536    STD     { int reapctl(int op, union reaper_info *data); }
index f600bf2..5b9a110 100644 (file)
@@ -63,6 +63,7 @@
 #include <sys/varsym.h>
 #include <sys/resourcevar.h>
 #ifdef _KERNEL
+#include <sys/reaper.h>
 #include <sys/globaldata.h>
 #endif
 #include <sys/systimer.h>
@@ -343,7 +344,8 @@ struct      proc {
        cpumask_t       p_vmm_cpumask;  /* cpus entering or in vmm */
        struct sys_upmap *p_upmap;      /* user RO mappable per-process page */
        forkid_t        p_forkid;       /* unique forkid */
-       void            *p_reserveds[4]; /* reserved for future */
+       struct sysreaper *p_reaper;     /* reaper control */
+       void            *p_reserveds[3]; /* reserved for future */
 };
 
 #define lwp_wchan      lwp_thread->td_wchan
@@ -577,6 +579,11 @@ void       lwpuserret(struct lwp *);
 void   lwpkthreaddeferred(void);
 void   proc_usermap(struct proc *p, int invfork);
 void   proc_userunmap(struct proc *p);
+void   reaper_hold(struct sysreaper *reap);
+void   reaper_drop(struct sysreaper *reap);
+struct sysreaper *reaper_exit(struct proc *p);
+void   reaper_init(struct proc *p, struct sysreaper *reap);
+struct proc *reaper_get(struct sysreaper *reap);
 
 u_int32_t      procrunnable (void);
 
diff --git a/sys/sys/reaper.h b/sys/sys/reaper.h
new file mode 100644 (file)
index 0000000..ea10fdf
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2014 The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Matthew Dillon <dillon@backplane.com>
+ *
+ * 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.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific, prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDERS 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_REAPER_H_
+#define _SYS_REAPER_H_
+
+#if defined(_KERNEL) || defined(_KERNEL_STRUCTURES)
+#include <sys/lock.h>
+#endif
+
+struct reaper_status {
+       uint32_t        flags;
+       uint32_t        refs;
+       long            reserved1[15];
+       pid_t           pid_head;
+       int             reserved2[15];
+};
+
+union reaper_info {
+       struct reaper_status    status;
+};
+
+#define _REAPER_PRESENT
+
+#define REAPER_OP_ACQUIRE      0x0001
+#define REAPER_OP_RELEASE      0x0002
+#define REAPER_OP_STATUS       0x0003
+
+#define REAPER_STAT_OWNED      0x00000001
+#define REAPER_STAT_REALINIT   0x00000002
+
+#if defined(_KERNEL) || defined(_KERNEL_STRUCTURES)
+
+struct proc;
+
+struct sysreaper {
+       struct lock     lock;           /* thread or topo access */
+       struct sysreaper *parent;       /* upward topology only */
+       struct proc     *p;             /* who the reaper is */
+       uint32_t        flags;          /* control flags */
+       u_int           refs;           /* shared structure refs */
+};
+
+#endif
+
+#if !defined(_KERNEL)
+
+int reapctl(int op, union reaper_info *data);
+
+#endif
+
+#endif
index 0cf2913..428439c 100644 (file)
 #define        SYS_lpathconf   533
 #define        SYS_vmm_guest_ctl       534
 #define        SYS_vmm_guest_sync_addr 535
-#define        SYS_MAXSYSCALL  536
+#define        SYS_reapctl     536
+#define        SYS_MAXSYSCALL  537
index 16e6f92..c78aa30 100644 (file)
@@ -299,4 +299,5 @@ MIASM =  \
        eaccess.o \
        lpathconf.o \
        vmm_guest_ctl.o \
-       vmm_guest_sync_addr.o
+       vmm_guest_sync_addr.o \
+       reapctl.o
index 61acfd0..71c54e3 100644 (file)
@@ -2265,6 +2265,13 @@ struct   vmm_guest_sync_addr_args {
        long *  dstaddr;        char dstaddr_[PAD_(long *)];
        long *  srcaddr;        char srcaddr_[PAD_(long *)];
 };
+struct reapctl_args {
+#ifdef _KERNEL
+       struct sysmsg sysmsg;
+#endif
+       int     op;     char op_[PAD_(int)];
+       union reaper *  data;   char data_[PAD_(union reaper *)];
+};
 
 #ifdef COMPAT_43
 
@@ -2871,6 +2878,7 @@ int       sys_eaccess (struct eaccess_args *);
 int    sys_lpathconf (struct lpathconf_args *);
 int    sys_vmm_guest_ctl (struct vmm_guest_ctl_args *);
 int    sys_vmm_guest_sync_addr (struct vmm_guest_sync_addr_args *);
+int    sys_reapctl (struct reapctl_args *);
 
 #endif /* !_SYS_SYSPROTO_H_ */
 #undef PAD_
index 4cef34a..4b976ee 100644 (file)
@@ -407,4 +407,5 @@ union sysunion {
        struct  lpathconf_args lpathconf;
        struct  vmm_guest_ctl_args vmm_guest_ctl;
        struct  vmm_guest_sync_addr_args vmm_guest_sync_addr;
+       struct  reapctl_args reapctl;
 };