]> Zhao Yanbai Git Server - minix.git/commitdiff
PM: add support for wait4(2) 03/3203/2
authorDavid van Moolenbroek <david@minix3.org>
Mon, 28 Sep 2015 11:11:55 +0000 (11:11 +0000)
committerDavid van Moolenbroek <david@minix3.org>
Tue, 29 Sep 2015 18:15:28 +0000 (18:15 +0000)
This patch adds support for the wait4 system call, and with that the
wait3 call as well.  The implementation is absolutely minimal: only
user and system times of the exited child are returned (with all other
rusage fields left zero), and there is no support for tracers.  Still,
this should cover the main use cases of wait4.

Change-Id: I7a04589a8423a23990ab39aa38e85d535556743a

17 files changed:
lib/libc/gen/Makefile.inc
minix/include/minix/callnr.h
minix/include/minix/ipc.h
minix/lib/libc/gen/wait.c [deleted file]
minix/lib/libc/gen/waitpid.c [deleted file]
minix/lib/libc/sys/Makefile.inc
minix/lib/libc/sys/wait4.c [new file with mode: 0644]
minix/lib/libminc/Makefile
minix/servers/pm/forkexit.c
minix/servers/pm/misc.c
minix/servers/pm/mproc.h
minix/servers/pm/proto.h
minix/servers/pm/table.c
minix/servers/pm/trace.c
minix/servers/pm/utility.c
minix/tests/test75.c
minix/usr.bin/trace/service/pm.c

index 7ea07c63d066df6b3533dab0e15aee5a2e0bbb78..74a54c21267361eb62e009894c89253a8385a083 100644 (file)
@@ -19,7 +19,6 @@ SRCS+= dhcp_gettag.c dhcp_settag.c fsversion.c gcov.c gcov_flush.c itoa.c \
 #      closefrom.c confstr.c extattr.c getdevmajor.c \
 #      pthread_atfork.c \
 #      sysctlbyname.c sysctlgetmibinfo.c sysctlnametomib.c
-#      wait3.c
 
 # To be ported
 # nlist.c nlist_aout.c nlist_coff.c nlist_ecoff.c nlist_elf32.c nlist_elf64.c
@@ -55,7 +54,7 @@ SRCS+=        _errno.c alarm.c alphasort.c arc4random.c assert.c basename.c clock.c \
        syslog.c telldir.c time.c \
        times.c toascii.c tolower_.c ttyname.c ttyslot.c toupper_.c ualarm.c \
        ulimit.c uname.c unvis.c usleep.c utime.c utimens.c utmp.c \
-       utmpx.c valloc.c vis.c wait.c waitpid.c warn.c warnx.c \
+       utmpx.c valloc.c vis.c wait.c wait3.c waitpid.c warn.c warnx.c \
        vwarn.c vwarnx.c verr.c verrx.c wordexp.c
 .endif
 
index 58ee494c81f380d6b9b05f1623152a8eb81903ca..52ba9bc2753de1bf331fcbadb4c7f620b7d5b60e 100644 (file)
@@ -13,7 +13,7 @@
 /* Message type 0 is traditionally reserved. */
 #define PM_EXIT                        (PM_BASE + 1)
 #define PM_FORK                        (PM_BASE + 2)
-#define PM_WAITPID             (PM_BASE + 3)
+#define PM_WAIT4               (PM_BASE + 3)
 #define PM_GETPID              (PM_BASE + 4)
 #define PM_SETUID              (PM_BASE + 5)
 #define PM_GETUID              (PM_BASE + 6)
index a3d9336ba98884327909078056d054b55477db4c..26c249180ea46a7f17627474e1e98c18be88b347 100644 (file)
@@ -573,10 +573,11 @@ _ASSERT_MSG_SIZE(mess_lc_pm_time);
 typedef struct {
        pid_t pid;
        int options;
+       vir_bytes addr;                 /* struct rusage * */
 
-       uint8_t padding[48];
-} mess_lc_pm_waitpid;
-_ASSERT_MSG_SIZE(mess_lc_pm_waitpid);
+       uint8_t padding[44];
+} mess_lc_pm_wait4;
+_ASSERT_MSG_SIZE(mess_lc_pm_wait4);
 
 typedef struct {
        cp_grant_id_t grant;
@@ -1519,8 +1520,8 @@ typedef struct {
        int status;
 
        uint8_t padding[52];
-} mess_pm_lc_waitpid;
-_ASSERT_MSG_SIZE(mess_pm_lc_waitpid);
+} mess_pm_lc_wait4;
+_ASSERT_MSG_SIZE(mess_pm_lc_wait4);
 
 typedef struct {
        int suid;
@@ -2090,7 +2091,7 @@ typedef struct noxfer_message {
                mess_lc_pm_sprof        m_lc_pm_sprof;
                mess_lc_pm_sysuname     m_lc_pm_sysuname;
                mess_lc_pm_time         m_lc_pm_time;
-               mess_lc_pm_waitpid      m_lc_pm_waitpid;
+               mess_lc_pm_wait4        m_lc_pm_wait4;
                mess_lc_readclock_rtcdev m_lc_readclock_rtcdev;
                mess_lc_svrctl          m_lc_svrctl;
                mess_lc_vfs_chown       m_lc_vfs_chown;
@@ -2196,7 +2197,7 @@ typedef struct noxfer_message {
                mess_pm_lc_ptrace       m_pm_lc_ptrace;
                mess_pm_lc_sigset       m_pm_lc_sigset;
                mess_pm_lc_time         m_pm_lc_time;
-               mess_pm_lc_waitpid      m_pm_lc_waitpid;
+               mess_pm_lc_wait4        m_pm_lc_wait4;
                mess_pm_lexec_exec_new  m_pm_lexec_exec_new;
                mess_pm_lsys_getepinfo  m_pm_lsys_getepinfo;
                mess_pm_lsys_getprocnr  m_pm_lsys_getprocnr;
diff --git a/minix/lib/libc/gen/wait.c b/minix/lib/libc/gen/wait.c
deleted file mode 100644 (file)
index f0755f2..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#include <sys/cdefs.h>
-#include <lib.h>
-#include "namespace.h"
-
-#include <string.h>
-#include <sys/wait.h>
-
-#ifdef __weak_alias
-__weak_alias(wait, _wait)
-#endif
-
-pid_t wait(int * status)
-{
-  message m;
-
-  memset(&m, 0, sizeof(m));
-  m.m_lc_pm_waitpid.pid = -1;
-  m.m_lc_pm_waitpid.options = 0;
-  if (_syscall(PM_PROC_NR, PM_WAITPID, &m) < 0) return(-1);
-  if (status != 0) *status = m.m_pm_lc_waitpid.status;
-  return(m.m_type);
-}
diff --git a/minix/lib/libc/gen/waitpid.c b/minix/lib/libc/gen/waitpid.c
deleted file mode 100644 (file)
index 89151fc..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#include <sys/cdefs.h>
-#include <lib.h>
-#include "namespace.h"
-
-#include <string.h>
-#include <sys/wait.h>
-
-#ifdef __weak_alias
-__weak_alias(waitpid, _waitpid)
-#endif
-
-pid_t waitpid(pid_t pid, int *status, int options)
-{
-  message m;
-
-  memset(&m, 0, sizeof(m));
-  m.m_lc_pm_waitpid.pid = pid;
-  m.m_lc_pm_waitpid.options = options;
-  if (_syscall(PM_PROC_NR, PM_WAITPID, &m) < 0) return(-1);
-  if (status != 0) *status = m.m_pm_lc_waitpid.status;
-  return m.m_type;
-}
index fb693d64a52b89da2c3f738ab62fd5e4a70ba2e1..91309782e63b833ded3ee9775e9c285a15812f43 100644 (file)
@@ -19,7 +19,8 @@ SRCS+=        accept.c access.c adjtime.c bind.c brk.c sbrk.c m_closefrom.c getsid.c \
        vectorio.c shutdown.c sigaction.c sigpending.c sigreturn.c sigsuspend.c\
        sigprocmask.c socket.c socketpair.c stat.c statvfs.c svrctl.c \
        symlink.c \
-       sync.c syscall.c sysuname.c truncate.c umask.c unlink.c write.c \
+       sync.c syscall.c sysuname.c truncate.c umask.c unlink.c \
+       wait4.c write.c \
        utimensat.c utimes.c futimes.c lutimes.c futimens.c \
        _exit.c _ucontext.c environ.c __getcwd.c vfork.c sizeup.c init.c \
        getrusage.c setrlimit.c setpgid.c
diff --git a/minix/lib/libc/sys/wait4.c b/minix/lib/libc/sys/wait4.c
new file mode 100644 (file)
index 0000000..4f9024d
--- /dev/null
@@ -0,0 +1,26 @@
+#include <sys/cdefs.h>
+#include <lib.h>
+#include "namespace.h"
+
+#include <string.h>
+#include <sys/wait.h>
+
+#ifdef __weak_alias
+__weak_alias(wait4, __wait450)
+#endif
+
+pid_t
+wait4(pid_t pid, int * status, int options, struct rusage * rusage)
+{
+       message m;
+
+       memset(&m, 0, sizeof(m));
+       m.m_lc_pm_wait4.pid = pid;
+       m.m_lc_pm_wait4.options = options;
+       m.m_lc_pm_wait4.addr = (vir_bytes)rusage;
+
+       if (_syscall(PM_PROC_NR, PM_WAIT4, &m) < 0) return(-1);
+
+       if (status != NULL) *status = m.m_pm_lc_wait4.status;
+       return m.m_type;
+}
index 28445f2c133daabb5273f4c5500f1f593300932c..d4f10c9b04f4d9c68e3b9ee4c11ee7587e16b696 100644 (file)
@@ -192,7 +192,7 @@ CLEANFILES+=        errlist.c
 .for f in \
        _errno.o \
        getprogname.o setprogname.o execle.o sleep.o time.o \
-       ctype_.o tolower_.o toupper_.o usleep.o sigsetops.o 
+       ctype_.o tolower_.o toupper_.o usleep.o waitpid.o sigsetops.o
 ${f} ${f:C/\.o/.bc/}:  ${LIBCDIR}/gen/${f:C/\.o/.c/}
 OBJS+= ${f}
 CLEANFILES+= ${f}
@@ -209,7 +209,7 @@ CPPFLAGS.tolower_.c+= -I${LIBCDIR}/locale
 CPPFLAGS.toupper_.c+= -I${LIBCDIR}/locale
 
 .for f in \
-       waitpid.o read_tsc_64.o fslib.o itoa.o oneC_sum.o
+       read_tsc_64.o fslib.o itoa.o oneC_sum.o
 ${f} ${f:C/\.o/.bc/}:  ${LIBMINIXCDIR}/gen/${f:C/\.o/.c/}
 OBJS+= ${f}
 CLEANFILES+= ${f}
@@ -289,7 +289,7 @@ CPPFLAGS.strcspn.c+=        -D_LIBC
        init.o kernel_utils.o link.o loadname.o lseek.o _mcontext.o mknod.o \
        mmap.o nanosleep.o open.o pread.o pwrite.o read.o sbrk.o \
        select.o setuid.o sigprocmask.o stack_utils.o stat.o stime.o \
-       syscall.o _ucontext.o umask.o unlink.o write.o \
+       syscall.o _ucontext.o umask.o unlink.o wait4.o write.o \
        kill.o
 ${f} ${f:C/\.o/.bc/}:  ${LIBMINIXCDIR}/sys/${f:C/\.o/.c/}
 OBJS+= ${f}
index 634f3a5302ca2cb2b746bd187fa8d0904712e807..d4394c9948d5dc2ead98e3975eee2d88ae5f3d1f 100644 (file)
@@ -1,11 +1,11 @@
 /* This file deals with creating processes (via FORK) and deleting them (via
- * EXIT/WAITPID).  When a process forks, a new slot in the 'mproc' table is
+ * EXIT/WAIT4).  When a process forks, a new slot in the 'mproc' table is
  * allocated for it, and a copy of the parent's core image is made for the
  * child.  Then the kernel and file system are informed.  A process is removed
  * from the 'mproc' table when two events have occurred: (1) it has exited or
- * been killed by a signal, and (2) the parent has done a WAITPID.  If the
+ * been killed by a signal, and (2) the parent has done a WAIT4.  If the
  * process exits first, it continues to occupy a slot until the parent does a
- * WAITPID.
+ * WAIT4.
  *
  * The entry points into this file are:
  *   do_fork:          perform the FORK system call
@@ -13,7 +13,7 @@
  *   do_exit:          perform the EXIT system call (by calling exit_proc())
  *   exit_proc:                actually do the exiting, and tell VFS about it
  *   exit_restart:     continue exiting a process after VFS has replied
- *   do_waitpid:       perform the WAITPID system call
+ *   do_wait4:         perform the WAIT4 system call
  *   wait_test:                check whether a parent is waiting for a child
  */
 
@@ -33,7 +33,7 @@
 
 static void zombify(struct mproc *rmp);
 static void check_parent(struct mproc *child, int try_cleanup);
-static void tell_parent(struct mproc *child);
+static int tell_parent(struct mproc *child, vir_bytes addr);
 static void tell_tracer(struct mproc *child);
 static void tracer_died(struct mproc *child);
 static void cleanup(register struct mproc *rmp);
@@ -447,24 +447,26 @@ int dump_core;                    /* flag indicating whether to dump core */
 }
 
 /*===========================================================================*
- *                             do_waitpid                                   *
+ *                             do_wait4                                     *
  *===========================================================================*/
-int do_waitpid()
+int do_wait4()
 {
 /* A process wants to wait for a child to terminate. If a child is already 
- * waiting, go clean it up and let this WAITPID call terminate.  Otherwise,
+ * waiting, go clean it up and let this WAIT4 call terminate.  Otherwise,
  * really wait. 
- * A process calling WAITPID never gets a reply in the usual way at the end
+ * A process calling WAIT4 never gets a reply in the usual way at the end
  * of the main loop (unless WNOHANG is set or no qualifying child exists).
  * If a child has already exited, the routine tell_parent() sends the reply
  * to awaken the caller.
  */
   register struct mproc *rp;
-  int i, pidarg, options, children;
+  vir_bytes addr;
+  int i, pidarg, options, children, waited_for;
 
   /* Set internal variables. */
-  pidarg  = m_in.m_lc_pm_waitpid.pid;          /* 1st param */
-  options = m_in.m_lc_pm_waitpid.options;      /* 3rd param */
+  pidarg  = m_in.m_lc_pm_wait4.pid;            /* 1st param */
+  options = m_in.m_lc_pm_wait4.options;                /* 3rd param */
+  addr    = m_in.m_lc_pm_wait4.addr;           /* 4th param */
   if (pidarg == 0) pidarg = -mp->mp_procgrp;   /* pidarg < 0 ==> proc grp */
 
   /* Is there a child waiting to be collected? At this point, pidarg != 0:
@@ -497,9 +499,12 @@ int do_waitpid()
                         */
                        for (i = 1; i < _NSIG; i++) {
                                if (sigismember(&rp->mp_sigtrace, i)) {
+                                       /* TODO: rusage support */
+
                                        sigdelset(&rp->mp_sigtrace, i);
 
-                                       mp->mp_reply.m_pm_lc_waitpid.status = W_STOPCODE(i);
+                                       mp->mp_reply.m_pm_lc_wait4.status =
+                                           W_STOPCODE(i);
                                        return(rp->mp_pid);
                                }
                        }
@@ -509,8 +514,9 @@ int do_waitpid()
        if (rp->mp_parent == who_p) {
                if (rp->mp_flags & ZOMBIE) {
                        /* This child meets the pid test and has exited. */
-                       tell_parent(rp); /* this child has already exited */
-                       if (!(rp->mp_flags & VFS_CALL))
+                       waited_for = tell_parent(rp, addr);
+
+                       if (waited_for && !(rp->mp_flags & VFS_CALL))
                                cleanup(rp);
                        return(SUSPEND);
                }
@@ -525,6 +531,7 @@ int do_waitpid()
        }
        mp->mp_flags |= WAITING;             /* parent wants to wait */
        mp->mp_wpid = (pid_t) pidarg;        /* save pid for later */
+       mp->mp_waddr = addr;                 /* save rusage addr for later */
        return(SUSPEND);                     /* do not reply, let it wait */
   } else {
        /* No child even meets the pid test.  Return error immediately. */
@@ -614,7 +621,8 @@ int try_cleanup;                    /* clean up the child when done? */
         */
   }
   else if (wait_test(p_mp, child)) {
-       tell_parent(child);
+       if (!tell_parent(child, p_mp->mp_waddr))
+               try_cleanup = FALSE; /* child is still there */
 
        /* The 'try_cleanup' flag merely saves us from having to be really
         * careful with statement ordering in exit_proc() and exit_restart().
@@ -631,11 +639,19 @@ int try_cleanup;                  /* clean up the child when done? */
 /*===========================================================================*
  *                             tell_parent                                  *
  *===========================================================================*/
-static void tell_parent(child)
-register struct mproc *child;  /* tells which process is exiting */
+static int tell_parent(struct mproc *child, vir_bytes addr)
 {
+/* Tell the parent of the given process that it has terminated, by satisfying
+ * the parent's ongoing wait4() call.  If the parent has requested the child
+ * tree's resource usage, copy that information out first.  The copy may fail;
+ * in that case, the parent's wait4() call will return with an error, but the
+ * child will remain a zombie.  Return TRUE if the child is cleaned up, or
+ * FALSE if the child is still a zombie.
+ */
+  struct rusage r_usage;
   int mp_parent;
   struct mproc *parent;
+  int r;
 
   mp_parent= child->mp_parent;
   if (mp_parent <= 0)
@@ -646,8 +662,26 @@ register struct mproc *child;      /* tells which process is exiting */
        panic("tell_parent: telling parent again");
   parent = &mproc[mp_parent];
 
+  /* See if we need to report resource usage to the parent. */
+  if (addr) {
+       /* We report only user and system times for now. TODO: support other
+        * fields, although this is tricky since the child process is already
+        * gone as far as the kernel and other services are concerned..
+        */
+       memset(&r_usage, 0, sizeof(r_usage));
+       set_rusage_times(&r_usage, child->mp_child_utime,
+           child->mp_child_stime);
+
+       if ((r = sys_datacopy(SELF, (vir_bytes)&r_usage, parent->mp_endpoint,
+           addr, sizeof(r_usage))) != OK) {
+               reply(child->mp_parent, r);
+
+               return FALSE; /* copy error - the child is still there */
+       }
+  }
+
   /* Wake up the parent by sending the reply message. */
-  parent->mp_reply.m_pm_lc_waitpid.status =
+  parent->mp_reply.m_pm_lc_wait4.status =
        W_EXITCODE(child->mp_exitstatus, child->mp_sigstatus);
   reply(child->mp_parent, child->mp_pid);
   parent->mp_flags &= ~WAITING;                /* parent no longer waiting */
@@ -659,6 +693,8 @@ register struct mproc *child;       /* tells which process is exiting */
    */
   parent->mp_child_utime += child->mp_child_utime;
   parent->mp_child_stime += child->mp_child_stime;
+
+  return TRUE; /* child has been waited for */
 }
 
 /*===========================================================================*
@@ -677,7 +713,9 @@ struct mproc *child;                        /* tells which process is exiting */
        panic("tell_tracer: child not a zombie");
   tracer = &mproc[mp_tracer];
 
-  tracer->mp_reply.m_pm_lc_waitpid.status =
+  /* TODO: rusage support */
+
+  tracer->mp_reply.m_pm_lc_wait4.status =
        W_EXITCODE(child->mp_exitstatus, (child->mp_sigstatus & 0377));
   reply(child->mp_tracer, child->mp_pid);
   tracer->mp_flags &= ~WAITING;                /* tracer no longer waiting */
index f2f0430e23fa20c37e70af8e99319679bf33d705..8f84d39715165af329263b3fb289551e14e7cda6 100644 (file)
@@ -410,7 +410,6 @@ do_getrusage(void)
 {
        clock_t user_time, sys_time;
        struct rusage r_usage;
-       u64_t usec;
        int r, children;
 
        if (m_in.m_lc_pm_rusage.who != RUSAGE_SELF &&
@@ -444,12 +443,7 @@ do_getrusage(void)
        }
 
        /* In both cases, convert from clock ticks to microseconds. */
-       usec = user_time * 1000000 / sys_hz();
-       r_usage.ru_utime.tv_sec = usec / 1000000;
-       r_usage.ru_utime.tv_usec = usec % 1000000;
-       usec = sys_time * 1000000 / sys_hz();
-       r_usage.ru_stime.tv_sec = usec / 1000000;
-       r_usage.ru_stime.tv_usec = usec % 1000000;
+       set_rusage_times(&r_usage, user_time, sys_time);
 
        /* Get additional fields from VM. */
        if ((r = vm_getrusage(who_e, &r_usage, children)) != OK)
index aadc3466fa7ea757d28854da2d1d130fad5e2077..6cfc099f13640cd0dfefc54e729283c4ffca25dc 100644 (file)
@@ -22,6 +22,7 @@ EXTERN struct mproc {
   endpoint_t mp_endpoint;      /* kernel endpoint id */
   pid_t mp_procgrp;            /* pid of process group (used for signals) */
   pid_t mp_wpid;               /* pid this process is waiting for */
+  vir_bytes mp_waddr;          /* struct rusage address while waiting */
   int mp_parent;               /* index of parent process */
   int mp_tracer;               /* index of tracer process, or NO_TRACER */
 
@@ -76,8 +77,8 @@ EXTERN struct mproc {
 
 /* Flag values */
 #define IN_USE         0x00001 /* set when 'mproc' slot in use */
-#define WAITING                0x00002 /* set by WAITPID system call */
-#define ZOMBIE         0x00004 /* waiting for parent to issue WAITPID call */
+#define WAITING                0x00002 /* set by WAIT4 system call */
+#define ZOMBIE         0x00004 /* waiting for parent to issue WAIT4 call */
 #define PROC_STOPPED   0x00008 /* process is stopped in the kernel */
 #define ALARM_ON       0x00010 /* set when SIGALRM timer started */
 #define EXITING                0x00020 /* set by EXIT, process is now exiting */
@@ -90,7 +91,7 @@ EXTERN struct mproc {
 #define PRIV_PROC      0x02000 /* system process, special privileges */
 #define PARTIAL_EXEC   0x04000 /* process got a new map but no content */
 #define TRACE_EXIT     0x08000 /* tracer is forcing this process to exit */
-#define TRACE_ZOMBIE   0x10000 /* waiting for tracer to issue WAITPID call */
+#define TRACE_ZOMBIE   0x10000 /* waiting for tracer to issue WAIT4 call */
 #define DELAY_CALL     0x20000 /* waiting for call before sending signal */
 #define TAINTED                0x40000 /* process is 'tainted' */
 
index e3d9f2b76c835279d51ae4e1837fd23129903f89..175ddbcdb84d82cc1ef58dffaf5f6bf469b1a54f 100644 (file)
@@ -22,7 +22,7 @@ int do_srv_fork(void);
 int do_exit(void);
 void exit_proc(struct mproc *rmp, int exit_status, int dump_core);
 void exit_restart(struct mproc *rmp, int dump_core);
-int do_waitpid(void);
+int do_wait4(void);
 int wait_test(struct mproc *rmp, struct mproc *child);
 
 /* getset.c */
@@ -88,3 +88,5 @@ struct mproc *find_proc(pid_t lpid);
 int nice_to_priority(int nice, unsigned *new_q);
 int pm_isokendpt(int ep, int *proc);
 void tell_vfs(struct mproc *rmp, message *m_ptr);
+void set_rusage_times(struct rusage *r_usage, clock_t user_time,
+       clock_t sys_time);
index 6853a0fc110aa147edb8b0dd091e7e055d00b502..d730a276f06df56f8efcb16864a829e7cd697d8c 100644 (file)
@@ -14,7 +14,7 @@
 int (* const call_vec[NR_PM_CALLS])(void) = {
        CALL(PM_EXIT)           = do_exit,              /* _exit(2) */
        CALL(PM_FORK)           = do_fork,              /* fork(2) */
-       CALL(PM_WAITPID)        = do_waitpid,           /* waitpid(2) */
+       CALL(PM_WAIT4)          = do_wait4,             /* wait4(2) */
        CALL(PM_GETPID)         = do_get,               /* get[p]pid(2) */
        CALL(PM_SETUID)         = do_set,               /* setuid(2) */
        CALL(PM_GETUID)         = do_get,               /* get[e]uid(2) */
index 6d11a4762fc15e98f932837bdbdd7baeb8bfe03b..e2498a8826eb7874b4b6924159ed94d44fe4e7d1 100644 (file)
@@ -265,10 +265,12 @@ int signo;
  
   rmp->mp_flags |= TRACE_STOPPED;
   if (wait_test(rpmp, rmp)) {
+       /* TODO: rusage support */
+
        sigdelset(&rmp->mp_sigtrace, signo);
 
        rpmp->mp_flags &= ~WAITING;     /* parent is no longer waiting */
-       rpmp->mp_reply.m_pm_lc_waitpid.status = W_STOPCODE(signo);
+       rpmp->mp_reply.m_pm_lc_wait4.status = W_STOPCODE(signo);
        reply(rmp->mp_tracer, rmp->mp_pid);
   }
 }
index 55c2900b275382f57303bd708221591717435a49..c8cd9a9662cc58437abe6be9e4938fb1f63baecc 100644 (file)
@@ -7,6 +7,7 @@
  *   nice_to_priority  convert nice level to priority queue
  *   pm_isokendpt:     check the validity of an endpoint
  *   tell_vfs:         send a request to VFS on behalf of a process
+ *   set_rusage_times: store user and system times in rusage structure
  */
 
 #include "pm.h"
@@ -136,3 +137,20 @@ message *m_ptr;
 
   rmp->mp_flags |= VFS_CALL;
 }
+
+/*===========================================================================*
+ *                             set_rusage_times                             *
+ *===========================================================================*/
+void
+set_rusage_times(struct rusage * r_usage, clock_t user_time, clock_t sys_time)
+{
+       u64_t usec;
+
+       usec = user_time * 1000000 / sys_hz();
+       r_usage->ru_utime.tv_sec = usec / 1000000;
+       r_usage->ru_utime.tv_usec = usec % 1000000;
+
+       usec = sys_time * 1000000 / sys_hz();
+       r_usage->ru_stime.tv_sec = usec / 1000000;
+       r_usage->ru_stime.tv_usec = usec % 1000000;
+}
index 11197a37d8a686a31e27f37bfe557281c990dc1a..208398b88bceb634a1455dc7d941bc8611117be8 100644 (file)
@@ -1,4 +1,4 @@
-/* Test 75 - getrusage functionality test.
+/* Test 75 - getrusage and wait4 test.
  */
 
 #include <sys/resource.h>
@@ -7,6 +7,7 @@
 #include <assert.h>
 #include <sys/types.h>
 #include <sys/wait.h>
+#include <sys/mman.h>
 #include <unistd.h>
 
 #include "common.h"
@@ -30,76 +31,137 @@ spin(void)
        struct timeval start_time;
        struct timeval end_time;
        unsigned int loop = 0;
-       if (gettimeofday(&start_time, NULL) == -1) {
-               e(1);
-               exit(1);
-       }
+       if (gettimeofday(&start_time, NULL) == -1) e(1);
        end_time = start_time;
        do {
                if ((++loop % 3000000000) == 0) {
-                       if (gettimeofday(&end_time, NULL) == -1) {
-                               e(1);
-                               exit(1);
-                       }
+                       if (gettimeofday(&end_time, NULL) == -1) e(1);
                }
        } while (start_time.tv_sec + 10 > end_time.tv_sec);
 }
 
-int
-main(int argc, char *argv[])
+/*
+ * Test getrusage(2).
+ */
+static void
+test75a(void)
 {
        struct rusage r_usage1;
        struct rusage r_usage2;
        struct rusage r_usage3;
        pid_t child;
        int status = 0;
-       start(75);
+
        if ((getrusage(RUSAGE_SELF + 1, &r_usage1) != -1 || errno != EINVAL) ||
-               (getrusage(RUSAGE_CHILDREN - 1, &r_usage1) != -1 ||
-                errno != EINVAL) || (getrusage(RUSAGE_SELF, NULL) != -1 ||
-                errno != EFAULT)) {
+           (getrusage(RUSAGE_CHILDREN - 1, &r_usage1) != -1 ||
+            errno != EINVAL) || (getrusage(RUSAGE_SELF, NULL) != -1 ||
+            errno != EFAULT))
                e(1);
-               exit(1);
-       }
+
        spin();
-       if (getrusage(RUSAGE_SELF, &r_usage1) != 0) {
-               e(1);
-               exit(1);
-       }
+       if (getrusage(RUSAGE_SELF, &r_usage1) != 0) e(1);
        CHECK_NOT_ZERO_FIELD(r_usage1, ru_utime.tv_sec);
        CHECK_NOT_ZERO_FIELD(r_usage1, ru_maxrss);
-       if (getrusage(RUSAGE_CHILDREN, &r_usage2) != 0) {
-               e(1);
-               exit(1);
-       }
+       if (getrusage(RUSAGE_CHILDREN, &r_usage2) != 0) e(1);
+
        if ((child = fork()) == 0) {
                /*
                 * We cannot do this part of the test in the parent, since
                 * start() calls system() which spawns a child process.
                 */
-               if (getrusage(RUSAGE_CHILDREN, &r_usage1) != 0) {
-                       e(1);
-                       exit(1);
-               }
+               if (getrusage(RUSAGE_CHILDREN, &r_usage1) != 0) e(1);
                CHECK_ZERO_FIELD(r_usage1, ru_utime.tv_sec);
                CHECK_ZERO_FIELD(r_usage1, ru_utime.tv_usec);
                spin();
-               exit(0);
+               exit(errct);
        } else {
-               if (child != waitpid(child, &status, 0)) {
-                       e(1);
-                       exit(1);
-               }
-               if (WEXITSTATUS(status) != 0) {
-                       e(1);
-                       exit(1);
-               }
-               if (getrusage(RUSAGE_CHILDREN, &r_usage3) != 0) {
-                       e(1);
-                       exit(1);
-               }
+               if (child != waitpid(child, &status, 0)) e(1);
+               if (WEXITSTATUS(status) != 0) e(1);
+               if (getrusage(RUSAGE_CHILDREN, &r_usage3) != 0) e(1);
                CHECK_NOT_ZERO_FIELD(r_usage3, ru_utime.tv_sec);
        }
+}
+
+/*
+ * Test the wait4 system call with good and bad rusage pointers, and with the
+ * wait4 either being satisfied immediately or blocking until the child exits:
+ * - mode 0: child has exited when parent calls wait4;
+ * - mode 1: parent blocks waiting for child, using a bad rusage pointer;
+ * - mode 2: parent blocks waiting for child, using a good rusage pointer.
+ */
+static void
+sub75b(int mode, void * bad_ptr)
+{
+       struct rusage r_usage;
+       pid_t pid;
+       int status;
+
+       pid = fork();
+
+       switch (pid) {
+       case -1:
+               e(0);
+               break;
+       case 0:
+               if (mode != 0)
+                       spin();
+               exit(0);
+       default:
+               if (mode == 0)
+                       sleep(1);
+
+               if (mode != 2) {
+                       /*
+                        * Try with a bad pointer.  This call may fail only
+                        * once the child has exited, but it must not clean up
+                        * the child.
+                        */
+                       if (wait4(-1, &status, 0, bad_ptr) != -1) e(0);
+                       if (errno != EFAULT) e(0);
+               }
+
+               r_usage.ru_nsignals = 1234; /* see if it's written at all */
+
+               /* Wait for the actual process. */
+               if (wait4(-1, &status, 0, &r_usage) != pid) e(0);
+               if (!WIFEXITED(status)) e(0);
+               if (WEXITSTATUS(status) != 0) e(0);
+
+               if (r_usage.ru_nsignals != 0) e(0);
+
+               /* Only check for actual time spent if the child spun. */
+               if (mode != 0)
+                       CHECK_NOT_ZERO_FIELD(r_usage, ru_utime.tv_sec);
+       }
+}
+
+/*
+ * Test wait4().
+ */
+static void
+test75b(void)
+{
+       void *ptr;
+
+       if ((ptr = mmap(NULL, sizeof(struct rusage), PROT_READ,
+           MAP_PRIVATE | MAP_ANON, -1, 0)) == MAP_FAILED) e(0);
+       if (munmap(ptr, sizeof(struct rusage)) != 0) e(0);
+       /* "ptr" is now a known-bad pointer */
+
+       sub75b(0, ptr);
+       sub75b(1, ptr);
+       sub75b(2, NULL);
+}
+
+int
+main(int argc, char *argv[])
+{
+
+       start(75);
+
+       test75a();
+       test75b();
+
        quit();
 
        return 0;
index 785180e30a3ec97a4edcc49911f41cc451dc990f..77303fa88897fca0f910268e129d25cb76d94ab4 100644 (file)
@@ -18,7 +18,7 @@ pm_exit_out(struct trace_proc * proc, const message * m_out)
        return CT_NORETURN;
 }
 
-static const struct flags waitpid_options[] = {
+static const struct flags wait4_options[] = {
        FLAG(WNOHANG),
        FLAG(WUNTRACED),
        FLAG(WALTSIG),
@@ -29,7 +29,7 @@ static const struct flags waitpid_options[] = {
 };
 
 static void
-put_waitpid_status(struct trace_proc * proc, const char * name, int status)
+put_wait4_status(struct trace_proc * proc, const char * name, int status)
 {
        const char *signame;
        int sig;
@@ -85,16 +85,39 @@ put_waitpid_status(struct trace_proc * proc, const char * name, int status)
 }
 
 static int
-pm_waitpid_out(struct trace_proc * proc, const message * m_out)
+pm_wait4_out(struct trace_proc * proc, const message * m_out)
 {
 
-       put_value(proc, "pid", "%d", m_out->m_lc_pm_waitpid.pid);
+       put_value(proc, "pid", "%d", m_out->m_lc_pm_wait4.pid);
 
        return CT_NOTDONE;
 }
 
 static void
-pm_waitpid_in(struct trace_proc * proc, const message * m_out,
+put_struct_rusage(struct trace_proc * proc, const char * name, int flags,
+       vir_bytes addr)
+{
+       struct rusage ru;
+
+       if (!put_open_struct(proc, name, flags, addr, &ru, sizeof(ru)))
+               return;
+
+       put_struct_timeval(proc, "ru_utime", PF_LOCADDR,
+           (vir_bytes)&ru.ru_utime);
+       put_struct_timeval(proc, "ru_stime", PF_LOCADDR,
+           (vir_bytes)&ru.ru_stime);
+
+       if (verbose > 0) {
+               put_value(proc, "ru_maxrss", "%ld", ru.ru_maxrss);
+               put_value(proc, "ru_minflt", "%ld", ru.ru_minflt);
+               put_value(proc, "ru_majflt", "%ld", ru.ru_majflt);
+       }
+
+       put_close_struct(proc, verbose > 0);
+}
+
+static void
+pm_wait4_in(struct trace_proc * proc, const message * m_out,
        const message * m_in, int failed)
 {
 
@@ -105,12 +128,12 @@ pm_waitpid_in(struct trace_proc * proc, const message * m_out,
         * unknown pointer.
         */
        if (!failed && m_in->m_type > 0)
-               put_waitpid_status(proc, "status",
-                   m_in->m_pm_lc_waitpid.status);
+               put_wait4_status(proc, "status", m_in->m_pm_lc_wait4.status);
        else
                put_field(proc, "status", "&..");
-       put_flags(proc, "options", waitpid_options, COUNT(waitpid_options),
-           "0x%x", m_out->m_lc_pm_waitpid.options);
+       put_flags(proc, "options", wait4_options, COUNT(wait4_options),
+           "0x%x", m_out->m_lc_pm_wait4.options);
+       put_struct_rusage(proc, "rusage", failed, m_out->m_lc_pm_wait4.addr);
        put_equals(proc);
        put_result(proc);
 }
@@ -1230,24 +1253,8 @@ static void
 pm_getrusage_in(struct trace_proc * proc, const message * m_out,
        const message * __unused m_in, int failed)
 {
-       struct rusage buf;
-
-       /* Inline; we will certainly not be reusing this anywhere else. */
-       if (put_open_struct(proc, "rusage", failed, m_out->m_lc_pm_rusage.addr,
-           &buf, sizeof(buf))) {
-               put_struct_timeval(proc, "ru_utime", PF_LOCADDR,
-                   (vir_bytes)&buf.ru_utime);
-               put_struct_timeval(proc, "ru_stime", PF_LOCADDR,
-                   (vir_bytes)&buf.ru_stime);
 
-               if (verbose > 0) {
-                       put_value(proc, "ru_maxrss", "%ld", buf.ru_maxrss);
-                       put_value(proc, "ru_minflt", "%ld", buf.ru_minflt);
-                       put_value(proc, "ru_majflt", "%ld", buf.ru_majflt);
-               }
-
-               put_close_struct(proc, verbose > 0);
-       }
+       put_struct_rusage(proc, "rusage", failed, m_out->m_lc_pm_rusage.addr);
        put_equals(proc);
        put_result(proc);
 }
@@ -1335,7 +1342,7 @@ pm_sprof_out(struct trace_proc * proc, const message * m_out)
 static const struct call_handler pm_map[] = {
        PM_CALL(EXIT) = HANDLER("exit", pm_exit_out, default_in),
        PM_CALL(FORK) = HANDLER("fork", default_out, default_in),
-       PM_CALL(WAITPID) = HANDLER("waitpid", pm_waitpid_out, pm_waitpid_in),
+       PM_CALL(WAIT4) = HANDLER("wait4", pm_wait4_out, pm_wait4_in),
        PM_CALL(GETPID) = HANDLER("getpid", default_out, pm_getpid_in),
        PM_CALL(SETUID) = HANDLER("setuid", pm_setuid_out, default_in),
        PM_CALL(GETUID) = HANDLER("getuid", default_out, pm_getuid_in),
@@ -1385,7 +1392,7 @@ static const struct call_handler pm_map[] = {
            pm_clock_gettime_in),
        PM_CALL(CLOCK_SETTIME) = HANDLER_NAME(pm_clock_settime_name,
            pm_clock_settime_out, default_in),
-       PM_CALL(GETRUSAGE) = HANDLER("pm_getrusage", pm_getrusage_out,
+       PM_CALL(GETRUSAGE) = HANDLER("getrusage", pm_getrusage_out,
            pm_getrusage_in),
        PM_CALL(REBOOT) = HANDLER("reboot", pm_reboot_out, default_in),
        PM_CALL(SVRCTL) = HANDLER("pm_svrctl", pm_svrctl_out, pm_svrctl_in),