# 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
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
/* 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)
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;
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;
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;
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;
+++ /dev/null
-#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);
-}
+++ /dev/null
-#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;
-}
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
--- /dev/null
+#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;
+}
.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}
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}
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}
/* 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
* 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
*/
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);
}
/*===========================================================================*
- * 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:
*/
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);
}
}
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);
}
}
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. */
*/
}
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().
/*===========================================================================*
* 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)
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 */
*/
parent->mp_child_utime += child->mp_child_utime;
parent->mp_child_stime += child->mp_child_stime;
+
+ return TRUE; /* child has been waited for */
}
/*===========================================================================*
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 */
{
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 &&
}
/* 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)
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 */
/* 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 */
#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' */
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 */
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);
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) */
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);
}
}
* 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"
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;
+}
-/* Test 75 - getrusage functionality test.
+/* Test 75 - getrusage and wait4 test.
*/
#include <sys/resource.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/wait.h>
+#include <sys/mman.h>
#include <unistd.h>
#include "common.h"
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;
return CT_NORETURN;
}
-static const struct flags waitpid_options[] = {
+static const struct flags wait4_options[] = {
FLAG(WNOHANG),
FLAG(WUNTRACED),
FLAG(WALTSIG),
};
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;
}
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)
{
* 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);
}
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);
}
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),
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),