diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc index 7ea07c63d..74a54c212 100644 --- a/lib/libc/gen/Makefile.inc +++ b/lib/libc/gen/Makefile.inc @@ -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 diff --git a/minix/include/minix/callnr.h b/minix/include/minix/callnr.h index 58ee494c8..52ba9bc27 100644 --- a/minix/include/minix/callnr.h +++ b/minix/include/minix/callnr.h @@ -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) diff --git a/minix/include/minix/ipc.h b/minix/include/minix/ipc.h index a3d9336ba..26c249180 100644 --- a/minix/include/minix/ipc.h +++ b/minix/include/minix/ipc.h @@ -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 index f0755f2f5..000000000 --- a/minix/lib/libc/gen/wait.c +++ /dev/null @@ -1,22 +0,0 @@ -#include -#include -#include "namespace.h" - -#include -#include - -#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 index 89151fcf2..000000000 --- a/minix/lib/libc/gen/waitpid.c +++ /dev/null @@ -1,22 +0,0 @@ -#include -#include -#include "namespace.h" - -#include -#include - -#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; -} diff --git a/minix/lib/libc/sys/Makefile.inc b/minix/lib/libc/sys/Makefile.inc index fb693d64a..91309782e 100644 --- a/minix/lib/libc/sys/Makefile.inc +++ b/minix/lib/libc/sys/Makefile.inc @@ -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 index 000000000..4f9024d9c --- /dev/null +++ b/minix/lib/libc/sys/wait4.c @@ -0,0 +1,26 @@ +#include +#include +#include "namespace.h" + +#include +#include + +#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; +} diff --git a/minix/lib/libminc/Makefile b/minix/lib/libminc/Makefile index 28445f2c1..d4f10c9b0 100644 --- a/minix/lib/libminc/Makefile +++ b/minix/lib/libminc/Makefile @@ -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} diff --git a/minix/servers/pm/forkexit.c b/minix/servers/pm/forkexit.c index 634f3a530..d4394c994 100644 --- a/minix/servers/pm/forkexit.c +++ b/minix/servers/pm/forkexit.c @@ -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 */ diff --git a/minix/servers/pm/misc.c b/minix/servers/pm/misc.c index f2f0430e2..8f84d3971 100644 --- a/minix/servers/pm/misc.c +++ b/minix/servers/pm/misc.c @@ -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) diff --git a/minix/servers/pm/mproc.h b/minix/servers/pm/mproc.h index aadc3466f..6cfc099f1 100644 --- a/minix/servers/pm/mproc.h +++ b/minix/servers/pm/mproc.h @@ -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' */ diff --git a/minix/servers/pm/proto.h b/minix/servers/pm/proto.h index e3d9f2b76..175ddbcdb 100644 --- a/minix/servers/pm/proto.h +++ b/minix/servers/pm/proto.h @@ -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); diff --git a/minix/servers/pm/table.c b/minix/servers/pm/table.c index 6853a0fc1..d730a276f 100644 --- a/minix/servers/pm/table.c +++ b/minix/servers/pm/table.c @@ -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) */ diff --git a/minix/servers/pm/trace.c b/minix/servers/pm/trace.c index 6d11a4762..e2498a882 100644 --- a/minix/servers/pm/trace.c +++ b/minix/servers/pm/trace.c @@ -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); } } diff --git a/minix/servers/pm/utility.c b/minix/servers/pm/utility.c index 55c2900b2..c8cd9a966 100644 --- a/minix/servers/pm/utility.c +++ b/minix/servers/pm/utility.c @@ -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; +} diff --git a/minix/tests/test75.c b/minix/tests/test75.c index 11197a37d..208398b88 100644 --- a/minix/tests/test75.c +++ b/minix/tests/test75.c @@ -1,4 +1,4 @@ -/* Test 75 - getrusage functionality test. +/* Test 75 - getrusage and wait4 test. */ #include @@ -7,6 +7,7 @@ #include #include #include +#include #include #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; diff --git a/minix/usr.bin/trace/service/pm.c b/minix/usr.bin/trace/service/pm.c index 785180e30..77303fa88 100644 --- a/minix/usr.bin/trace/service/pm.c +++ b/minix/usr.bin/trace/service/pm.c @@ -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),