]> Zhao Yanbai Git Server - minix.git/commitdiff
Implement getrusage 69/669/2
authorXiaoguang Sun <sun.xiaoguang@yoyosys.com>
Tue, 25 Jun 2013 12:41:01 +0000 (20:41 +0800)
committerGerrit Code Review <gerrit@gerrit>
Mon, 1 Jul 2013 21:00:47 +0000 (23:00 +0200)
Implement getrusage.
These fields of struct rusage are not supported and always set to zero at this time
long ru_nswap;           /* swaps */
long ru_inblock;         /* block input operations */
long ru_oublock;         /* block output operations */
long ru_msgsnd;          /* messages sent */
long ru_msgrcv;          /* messages received */
long ru_nvcsw;           /* voluntary context switches */
long ru_nivcsw;          /* involuntary context switches */

test75.c is the unit test for this new function

Change-Id: I3f1eb69de1fce90d087d76773b09021fc6106539

41 files changed:
distrib/sets/lists/minix/mi
include/minix/callnr.h
include/minix/com.h
include/minix/syslib.h
kernel/proc.c
kernel/proc.h
kernel/proto.h
kernel/system.c
kernel/system/do_fork.c
kernel/system/do_getinfo.c
lib/libc/sys-minix/Makefile.inc
lib/libc/sys-minix/getrusage.c [new file with mode: 0644]
lib/libc/sys/Makefile.inc
lib/libexec/exec_elf.c
lib/libexec/libexec.h
servers/pm/misc.c
servers/pm/proto.h
servers/pm/table.c
servers/vfs/exec.c
servers/vfs/fproc.h
servers/vfs/misc.c
servers/vfs/proto.h
servers/vfs/table.c
servers/vm/exit.c
servers/vm/main.c
servers/vm/mem_anon.c
servers/vm/mem_anon_contig.c
servers/vm/mem_cache.c
servers/vm/mem_directphys.c
servers/vm/mem_file.c
servers/vm/mem_shared.c
servers/vm/memtype.h
servers/vm/pagefaults.c
servers/vm/proto.h
servers/vm/region.c
servers/vm/utility.c
servers/vm/vmproc.h
sys/sys/resource.h
test/Makefile
test/run
test/test75.c [new file with mode: 0644]

index ce34f47dc5e8627936ae503cb8f9204ac5ed9333..8701b038d579a4bd5477eac24ef8b8588369775f 100644 (file)
 ./usr/man/man2/getpeername.2           minix-sys
 ./usr/man/man2/getpid.2                        minix-sys
 ./usr/man/man2/getpriority.2           minix-sys
+./usr/man/man2/getrusage.2             minix-sys
 ./usr/man/man2/getsockname.2           minix-sys
 ./usr/man/man2/getsockopt.2            minix-sys
 ./usr/man/man2/gettimeofday.2          minix-sys
 ./usr/tests/minix-posix/test72         minix-sys
 ./usr/tests/minix-posix/test73         minix-sys
 ./usr/tests/minix-posix/test74         minix-sys
+./usr/tests/minix-posix/test75         minix-sys
 ./usr/tests/minix-posix/test7          minix-sys
 ./usr/tests/minix-posix/test8          minix-sys
 ./usr/tests/minix-posix/test9          minix-sys
index 0ec74931b893594888273318980f5af4223d0378..629f04ec267a6b48f7fa4b188198317644da68bb 100644 (file)
@@ -1,4 +1,4 @@
-#define NCALLS          118    /* number of system calls allowed */
+#define NCALLS          124    /* number of system calls allowed */
 
 /* In case it isn't obvious enough: this list is sorted numerically. */
 #define EXIT              1 
                                 * really a standalone call.
                                 */
 #define MAPDRIVER      122     /* to VFS, map a device */
+#define GETRUSAGE      123     /* to PM, VFS */
index 08496d220622bdbb77d2d827688c61355a0a0a47..59bab8112bae2f1cf66c4f79dcbfaee84ddb8819 100644 (file)
 #   define GET_IDLETSC   21    /* get cumulative idle time stamp counter */
 #   define GET_CPUINFO    23    /* get information about cpus */
 #   define GET_REGS      24    /* get general process registers */
+#   define GET_RUSAGE    25    /* get resource usage */
 #define I_ENDPT        m7_i4   /* calling process (may only be SELF) */
 #define I_VAL_PTR      m7_p1   /* virtual address at caller */ 
 #define I_VAL_LEN      m7_i1   /* max length of value */
 
 #define VM_VFS_MMAP             (VM_RQ_BASE+46)
 
+#define VM_GETRUSAGE           (VM_RQ_BASE+47)
+
 /* Total. */
-#define NR_VM_CALLS                            47
+#define NR_VM_CALLS                            48
 #define VM_CALL_MASK_SIZE                      BITMAP_CHUNKS(NR_VM_CALLS)
 
 /* not handled as a normal VM call, thus at the end of the reserved rage */
 #  define BDEV_NOFLAGS         0x00    /* no flags are set */
 #  define BDEV_FORCEWRITE      0x01    /* force write to disk immediately */
 
+/* Field names for GETRUSAGE related calls */
+#define RU_ENDPT       m1_i1   /* indicates a process for sys_getrusage */
+#define RU_WHO         m1_i1   /* who argument in getrusage call */
+#define RU_RUSAGE_ADDR m1_p1   /* pointer to struct rusage */
+
 /* _MINIX_COM_H */
index a5fcefc6f5dc5236d7e72312c3bb309487b28e6b..86379009137f34a4fe7553d82fc71ed926c43db9 100644 (file)
@@ -17,6 +17,7 @@
 /* Forward declaration */
 struct reg86u;
 struct rs_pci;
+struct rusage;
 
 #define SYSTASK SYSTEM
 
@@ -178,6 +179,7 @@ int send_taskreply(endpoint_t who, endpoint_t endpoint, int status);
 #define sys_getpriv(dst, nr)   sys_getinfo(GET_PRIV, dst, 0,0, nr)
 #define sys_getidletsc(dst)    sys_getinfo(GET_IDLETSC, dst, 0,0,0)
 #define sys_getregs(dst,nr)    sys_getinfo(GET_REGS, dst, 0,0, nr)
+#define sys_getrusage(dst, nr)  sys_getinfo(GET_RUSAGE, dst, 0,0, nr)
 int sys_getinfo(int request, void *val_ptr, int val_len, void *val_ptr2,
        int val_len2);
 int sys_whoami(endpoint_t *ep, char *name, int namelen, int
index 6dcaf9125d01ea46fcd4b86acaf09a999f0f5a33..140ac4724f510210dd24184319a3490f502f04b5 100644 (file)
@@ -1906,3 +1906,8 @@ void ser_dump_proc()
                 print_proc_recursive(pp);
         }
 }
+
+void increase_proc_signals(struct proc *p)
+{
+       p->p_signal_received++;
+}
index 43939693761a66b16c6a3ed35e3abd3bb279411c..2f749b5c7c86414bb044c554812a1ad29feb2dca 100644 (file)
@@ -126,6 +126,8 @@ struct proc {
    */
   struct { reg_t r1, r2, r3; } p_defer;
 
+  u64_t p_signal_received;
+
 #if DEBUG_TRACE
   int p_schedules;
 #endif
index 7952922ddb4ff5469ea5e63b34de0a587ea39ade..ed382c7b982a117e55625349eeb695bdb6d8f9da 100644 (file)
@@ -76,6 +76,7 @@ int isokendpt_f(endpoint_t e, int *p, int f);
 #endif
 void proc_no_time(struct proc *p);
 void reset_proc_accounting(struct proc *p);
+void increase_proc_signals(struct proc *p);
 void flag_account(struct proc *p, int flag);
 int try_deliver_senda(struct proc *caller_ptr, asynmsg_t *table, size_t
        size);
index caafd994350a9a958f761402fa887011a92d98a5..423b353b17982d0eb93b43c345385c8e359aa704 100644 (file)
@@ -373,6 +373,7 @@ int send_sig(endpoint_t ep, int sig_nr)
   priv = priv(rp);
   if(!priv) return ENOENT;
   sigaddset(&priv->s_sig_pending, sig_nr);
+  increase_proc_signals(rp);
   mini_notify(proc_addr(SYSTEM), rp->p_endpoint);
 
   return OK;
@@ -434,6 +435,7 @@ int sig_nr;                 /* signal to be sent */
   /* Check if the signal is already pending. Process it otherwise. */
   if (! sigismember(&rp->p_pending, sig_nr)) {
       sigaddset(&rp->p_pending, sig_nr);
+       increase_proc_signals(rp);
       if (! (RTS_ISSET(rp, RTS_SIGNALED))) {           /* other pending */
          RTS_SET(rp, RTS_SIGNALED | RTS_SIG_PENDING);
           if(OK != send_sig(sig_mgr, SIGKSIG))
index f30927025cefcfcb8b1531f07b8b2e8028b9fa21..c58622102ccca521b3e7784bb0e1095e465af1d5 100644 (file)
@@ -90,6 +90,7 @@ int do_fork(struct proc * caller, message * m_ptr)
   make_zero64(rpc->p_cycles);
   make_zero64(rpc->p_kcall_cycles);
   make_zero64(rpc->p_kipc_cycles);
+  rpc->p_signal_received = 0;
 
   /* If the parent is a privileged process, take away the privileges from the 
    * child process and inhibit it from running by setting the NO_PRIV flag.
index 19ab73c147ebbc4ddc69190692a0a1572ba381b9..fef7ce5a441ed2477c085e8e5ff1b73dbd7b9e4b 100644 (file)
@@ -17,6 +17,7 @@
 #if USE_GETINFO
 
 #include <minix/u64.h>
+#include <sys/resource.h>
 
 /*===========================================================================*
  *                             update_idle_time                             *
@@ -47,6 +48,7 @@ int do_getinfo(struct proc * caller, message * m_ptr)
   int nr_e, nr, r;
   int wipe_rnd_bin = -1;
   struct proc *p;
+  struct rusage r_usage;
 
   /* Set source address and length based on request type. */
   switch (m_ptr->I_REQUEST) {
@@ -180,6 +182,32 @@ int do_getinfo(struct proc * caller, message * m_ptr)
         src_vir = (vir_bytes) &idl->p_cycles;
         break;
     }
+    case GET_RUSAGE: {
+       struct proc *target = NULL;
+       int target_slot = 0;
+       u64_t usec;
+        nr_e = (m_ptr->I_VAL_LEN2_E == SELF) ?
+            caller->p_endpoint : m_ptr->I_VAL_LEN2_E;
+
+       if (!isokendpt(nr_e, &target_slot))
+               return EINVAL;
+
+       target = proc_addr(target_slot);
+       if (isemptyp(target))
+               return EINVAL;
+
+       length = sizeof(r_usage);
+       memset(&r_usage, 0, sizeof(r_usage));
+       usec = target->p_user_time * 1000000 / system_hz;
+       r_usage.ru_utime.tv_sec = usec / 1000000;
+       r_usage.ru_utime.tv_usec = usec % 100000;
+       usec = target->p_sys_time * 1000000 / system_hz;
+       r_usage.ru_stime.tv_sec = usec / 1000000;
+       r_usage.ru_stime.tv_usec = usec % 100000;
+       r_usage.ru_nsignals = target->p_signal_received;
+       src_vir = (vir_bytes) &r_usage;
+       break;
+    }
     default:
        printf("do_getinfo: invalid request %d\n", m_ptr->I_REQUEST);
         return(EINVAL);
index 98a208fab0a2857ebf7f639b1a565d2b914ba16f..890b66d876036ecf75567b6b734c1198cf104e50 100644 (file)
@@ -18,7 +18,8 @@ SRCS+=        accept.c access.c adjtime.c bind.c brk.c sbrk.c m_closefrom.c getsid.c \
        sigprocmask.c socket.c socketpair.c stat.c statvfs.c symlink.c \
        sync.c syscall.c sysuname.c truncate.c umask.c unlink.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
+       _exit.c _ucontext.c environ.c __getcwd.c vfork.c sizeup.c init.c \
+       getrusage.c
 
 # Minix specific syscalls.
 SRCS+= cprofile.c lseek64.c sprofile.c _mcontext.c
diff --git a/lib/libc/sys-minix/getrusage.c b/lib/libc/sys-minix/getrusage.c
new file mode 100644 (file)
index 0000000..271eb24
--- /dev/null
@@ -0,0 +1,32 @@
+#include <sys/cdefs.h>
+#include "namespace.h"
+#include <lib.h>
+
+#include <unistd.h>
+#include <sys/resource.h>
+
+int getrusage(int who, struct rusage *r_usage)
+{
+       int rc;
+       message m;
+       m.RU_WHO = who;
+       m.RU_RUSAGE_ADDR = r_usage;
+
+       if (r_usage == NULL) {
+               errno = EFAULT;
+               return -1;
+       }
+       if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       memset(r_usage, 0, sizeof(struct rusage));
+       if ((rc = _syscall(PM_PROC_NR, GETRUSAGE, &m)) < 0)
+               return rc;
+       m.RU_RUSAGE_ADDR = r_usage;
+       if ((rc = _syscall(VFS_PROC_NR, GETRUSAGE, &m)) < 0)
+               return rc;
+       m.RU_RUSAGE_ADDR = r_usage;
+       return _syscall(VM_PROC_NR, VM_GETRUSAGE, &m);
+}
index b20b7ea66afc706d448258e2831dea830b109bb5..2fa88dfd573ada298d196c2ef4d63f87cb16ac12 100644 (file)
@@ -228,7 +228,7 @@ MAN+=       accept.2 access.2 acct.2 bind.2 brk.2 chdir.2 \
        flock.2 fork.2 fsync.2 getcontext.2 getdents.2 \
        getfh.2 getvfsstat.2 getgid.2 getgroups.2 \
        getitimer.2 getlogin.2 getpeername.2 getpgrp.2 getpid.2 \
-       getpriority.2 getrlimit.2 getrusage.2 getsid.2 getsockname.2 \
+       getpriority.2 getrlimit.2 getsid.2 getsockname.2 \
        getsockopt.2 gettimeofday.2 getuid.2 intro.2 ioctl.2 issetugid.2 \
        kill.2 kqueue.2 ktrace.2 \
        lfs_bmapv.2 lfs_markv.2 lfs_segclean.2 lfs_segwait.2 \
@@ -244,7 +244,7 @@ MAN+=       accept.2 access.2 acct.2 bind.2 brk.2 chdir.2 \
        mprotect.2 mremap.2 msgctl.2 msgget.2 msgrcv.2 msgsnd.2 msync.2 \
        munmap.2 nanosleep.2 nfssvc.2 ntp_adjtime.2 open.2 pathconf.2 pipe.2 
 .else
-MAN+=  adjtime.2 clock_settime.2 pipe.2 
+MAN+=  adjtime.2 clock_settime.2 pipe.2 getrusage.2
 .endif # !defined(__MINIX)
 .if !defined(__MINIX)
 MAN+=  pmc_control.2 poll.2 posix_fadvise.2 profil.2 ptrace.2 __quotactl.2 \
index 06c1bfd7d466da15ec77fc1273913d78ca4e4b9d..131f6deb2e485d0c1192b899abea766e195577b4 100644 (file)
@@ -228,6 +228,11 @@ int libexec_load_elf(struct exec_info *execi)
                if(first || startv > vaddr) startv = vaddr;
                first = 0;
 
+               if ((ph->p_flags & PF_X) != 0 && execi->text_size < seg_membytes)
+                       execi->text_size = seg_membytes;
+               else
+                       execi->data_size = seg_membytes;
+
                if(try_mmap && execi->memmap(execi, vaddr, fbytes, foffset, clearend, mmap_prot) == OK) {
 #if ELF_DEBUG
                        printf("libexec: mmap 0x%lx-0x%lx done, clearend 0x%x\n",
index 8597e74c31bba4c4864192bbee1b403d6248818e..b9a8fe15feb592e466938a88935f4abbbd2f44e3 100644 (file)
@@ -32,6 +32,8 @@ struct exec_info {
     int allow_setuid;                   /* Allow set{u,g}id execution? */
     vir_bytes stack_size;              /* Desired stack size */
     vir_bytes load_offset;             /* Desired load offset */
+    vir_bytes text_size;               /* Text segment size */
+    vir_bytes data_size;               /* Data segment size */
     off_t filesize;                    /* How big is the file */
 
     /* Callback pointers for use by libexec */
index c3a198b39caec861df2b70ad3c50bb84c29ec83b..0576a55135b081e465544e710ecc4834ded66ead 100644 (file)
@@ -492,3 +492,31 @@ void *brk_addr;
        _brksize = brk_addr;
        return 0;
 }
+
+/*===========================================================================*
+ *                             do_getrusage                                 *
+ *===========================================================================*/
+int do_getrusage()
+{
+       int res = 0;
+       clock_t user_time = 0;
+       clock_t sys_time = 0;
+       struct rusage r_usage;
+       u64_t usec;
+       if (m_in.RU_WHO != RUSAGE_SELF && m_in.RU_WHO != RUSAGE_CHILDREN)
+               return EINVAL;
+       if ((res = sys_getrusage(&r_usage, who_e)) < 0)
+               return res;
+
+       if (m_in.RU_WHO == RUSAGE_CHILDREN) {
+               usec = mp->mp_child_utime * 1000000 / sys_hz();
+               r_usage.ru_utime.tv_sec = usec / 1000000;
+               r_usage.ru_utime.tv_usec = usec % 1000000;
+               usec = mp->mp_child_stime * 1000000 / sys_hz();
+               r_usage.ru_stime.tv_sec = usec / 1000000;
+               r_usage.ru_stime.tv_usec = usec % 1000000;
+       }
+
+       return sys_datacopy(SELF, &r_usage, who_e,
+               (vir_bytes) m_in.RU_RUSAGE_ADDR, (vir_bytes) sizeof(r_usage));
+}
index 73e8a4a69dffa0772a2c8e90d180956d0daccf2c..0dc30709f069a070bb407cccc6354329f2f0e60f 100644 (file)
@@ -56,6 +56,7 @@ int do_getepinfo(void);
 int do_getepinfo_o(void);
 int do_svrctl(void);
 int do_getsetpriority(void);
+int do_getrusage(void);
 
 /* schedule.c */
 void sched_init(void);
index d1c2075a1feee0b7d6c2711d3ef43bcd0ffa0030..b9007553ba8b7eec5556878914bb324e38a3706e 100644 (file)
@@ -129,6 +129,12 @@ int (*call_vec[])(void) = {
        do_gettime,     /* 115 = clock_gettime */
        do_settime,     /* 116 = clock_settime */
        no_sys,         /* 117 = (vmcall) */
+       no_sys,         /* 118 = unsused */
+       no_sys,         /* 119 = unsused */
+       no_sys,         /* 120 = unsused */
+       no_sys,         /* 121 = (task reply) */
+       no_sys,         /* 122 = (map driver ) */
+       do_getrusage,   /* 123 = getrusage */
 };
 /* This should not fail with "array size is negative": */
 extern int dummy[sizeof(call_vec) == NCALLS * sizeof(call_vec[0]) ? 1 : -1];
index 8a58a77ee8b468fb28d36b80c8a28643b1677e7f..c0bbe58ae68e6c1459cdf744ebcba163b3f2fef4 100644 (file)
@@ -253,6 +253,8 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len,
 
   okendpt(proc_e, &slot);
   rfp = fp = &fproc[slot];
+  rfp->text_size = 0;
+  rfp->data_size = 0;
 
   lookup_init(&resolve, fullpath, PATH_NOFLAGS, &execi.vmp, &execi.vp);
 
@@ -409,6 +411,8 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len,
 
   /* Remember the new name of the process */
   strlcpy(rfp->fp_name, execi.args.progname, PROC_NAME_LEN);
+  rfp->text_size = execi.args.text_size;
+  rfp->data_size = execi.args.data_size;
 
 pm_execfinal:
   if(newfilp) unlock_filp(newfilp);
index 9ef7acbd03ebe62accbce25b23124fff2229aab3..3f9ff28e97971a0110368328eed272c3fbc2091c 100644 (file)
@@ -50,6 +50,9 @@ EXTERN struct fproc {
   int fp_vp_rdlocks;           /* number of read-only locks on vnodes */
   int fp_vmnt_rdlocks;         /* number of read-only locks on vmnts */
 #endif
+
+  vir_bytes text_size;         /* text segment size of current process */
+  vir_bytes data_size;         /* data segment size of current process */
 } fproc[NR_PROCS];
 
 /* fp_flags */
index 6d9a7269e0c7d123f9c3eced536696182aabe9f7..7f8dede773a3900aa0c5a5ff662708251f00fe27 100644 (file)
@@ -30,6 +30,7 @@
 #include <minix/u64.h>
 #include <sys/ptrace.h>
 #include <sys/svrctl.h>
+#include <sys/resource.h>
 #include "file.h"
 #include "fproc.h"
 #include "scratchpad.h"
@@ -939,3 +940,24 @@ void panic_hook(void)
   mthread_stacktraces(); 
 }         
 
+/*===========================================================================*
+ *                             do_getrusage                                 *
+ *===========================================================================*/
+int do_getrusage(message *UNUSED(m_out))
+{
+       int res;
+       struct rusage r_usage;
+
+       if ((res = sys_datacopy(who_e, (vir_bytes) m_in.RU_RUSAGE_ADDR, SELF,
+               (vir_bytes) &r_usage, (vir_bytes) sizeof(r_usage))) < 0)
+               return res;
+
+       r_usage.ru_inblock = 0;
+       r_usage.ru_oublock = 0;
+       r_usage.ru_ixrss = fp->text_size;
+       r_usage.ru_idrss = fp->data_size;
+       r_usage.ru_isrss = DEFAULT_STACK_LIMIT;
+
+       return sys_datacopy(SELF, (vir_bytes) &r_usage, who_e,
+               (vir_bytes) m_in.RU_RUSAGE_ADDR, (phys_bytes) sizeof(r_usage));
+}
index 339949042009289be355645a22527d22c3c29f7f..6a048c25d469d09c497596d060468b3559f577d4 100644 (file)
@@ -147,6 +147,7 @@ int do_vm_call(message *m_out);
 int pm_dumpcore(endpoint_t proc_e, int sig, vir_bytes exe_name);
 void * ds_event(void *arg);
 int dupvm(struct fproc *fp, int pfd, int *vmfd, struct filp **f);
+int do_getrusage(message *m_out);
 
 /* mount.c */
 int do_fsready(message *m_out);
index 6aa4f734b3138d91084d60c82a6ce626e8a72a2f..586c055d58e40582103dec15998c19a317378e0a 100644 (file)
@@ -133,6 +133,12 @@ int (*call_vec[])(message *m_out) = {
        no_sys,         /* 115 = (clock_gettime) */
        no_sys,         /* 116 = (clock_settime) */
        do_vm_call,     /* 117 = call from vm */
+       no_sys,         /* 118 = unsused */
+       no_sys,         /* 119 = unsused */
+       no_sys,         /* 120 = unsused */
+       no_sys,         /* 121 = (task reply) */
+       no_sys,         /* 122 = (map driver ) */
+       do_getrusage,   /* 123 = getrusage */
 };
 /* This should not fail with "array size is negative": */
 extern int dummy[sizeof(call_vec) == NCALLS * sizeof(call_vec[0]) ? 1 : -1];
index f287b327a8720f1343055fa97105e07ed7526e71..11cfcc94ba8313aaed7cd3a506120c01f2fad2a1 100644 (file)
 #include "util.h"
 #include "sanitycheck.h"
 
+static void reset_vm_rusage(struct vmproc *vmp)
+{
+       vmp->vm_total = 0;
+       vmp->vm_total_max = 0;
+       vmp->vm_minor_page_fault = 0;
+       vmp->vm_major_page_fault = 0;
+}
+
 void free_proc(struct vmproc *vmp)
 {
        map_free_proc(vmp);
@@ -33,6 +41,7 @@ void free_proc(struct vmproc *vmp)
        vmp->vm_bytecopies = 0;
 #endif
        vmp->vm_region_top = 0;
+       reset_vm_rusage(vmp);
 }
 
 void clear_proc(struct vmproc *vmp)
@@ -43,6 +52,7 @@ void clear_proc(struct vmproc *vmp)
        vmp->vm_bytecopies = 0;
 #endif
        vmp->vm_region_top = 0;
+       reset_vm_rusage(vmp);
 }
 
 /*===========================================================================*
index 3f494033aca9e8241ed9b582a03754c1612616b0..95e64486d007bc1f97254e45037304968d019f04 100644 (file)
@@ -443,6 +443,9 @@ void init_vm(void)
        CALLMAP(VM_MAPCACHEPAGE, do_mapcache);
        CALLMAP(VM_SETCACHEPAGE, do_setcache);
 
+       /* getrusage */
+       CALLMAP(VM_GETRUSAGE, do_getrusage);
+
        /* Initialize the structures for queryexit */
        init_query_exit();
 
index 9adc52419082bc523601add791385e4ecc280a73..5158f882df9485ec2454405c7210bf7ee65d16cb 100644 (file)
@@ -22,7 +22,8 @@ static void anon_split(struct vmproc *vmp, struct vir_region *vr,
 static int anon_lowshrink(struct vir_region *vr, vir_bytes len);
 static int anon_unreference(struct phys_region *pr);
 static int anon_pagefault(struct vmproc *vmp, struct vir_region *region, 
-       struct phys_region *ph, int write, vfs_callback_t cb, void *, int);
+       struct phys_region *ph, int write, vfs_callback_t cb, void *state,
+       int len, int *io);
 static int anon_sanitycheck(struct phys_region *pr, char *file, int line);
 static int anon_writable(struct phys_region *pr);
 static int anon_resize(struct vmproc *vmp, struct vir_region *vr, vir_bytes l);
@@ -51,7 +52,8 @@ static int anon_unreference(struct phys_region *pr)
 }
 
 static int anon_pagefault(struct vmproc *vmp, struct vir_region *region,
-       struct phys_region *ph, int write, vfs_callback_t cb, void *st, int l)
+       struct phys_region *ph, int write, vfs_callback_t cb, void *state,
+       int len, int *io)
 {
        phys_bytes new_page, new_page_cl;
        u32_t allocflags;
index 1f2750d18fe54e3ab9b1818eec31845364e76275..127ee4cfa4ce54e10b6ae93f4242cdec26b2a363 100644 (file)
@@ -11,7 +11,8 @@
 static int anon_contig_reference(struct phys_region *, struct phys_region *);
 static int anon_contig_unreference(struct phys_region *pr);
 static int anon_contig_pagefault(struct vmproc *vmp, struct vir_region *region, 
-       struct phys_region *ph, int write, vfs_callback_t cb, void *st, int);
+       struct phys_region *ph, int write, vfs_callback_t cb, void *state,
+       int len, int *io);
 static int anon_contig_sanitycheck(struct phys_region *pr, char *file, int line);
 static int anon_contig_writable(struct phys_region *pr);
 static int anon_contig_resize(struct vmproc *vmp, struct vir_region *vr, vir_bytes l);
@@ -29,7 +30,8 @@ struct mem_type mem_type_anon_contig = {
 };
 
 static int anon_contig_pagefault(struct vmproc *vmp, struct vir_region *region,
-       struct phys_region *ph, int write, vfs_callback_t cb, void *s, int l)
+       struct phys_region *ph, int write, vfs_callback_t cb, void *state,
+       int len, int *io)
 {
        panic("anon_contig_pagefault: pagefault cannot happen");
 }
index 7bc0bc24e7a4a57c01b8ffd35ec29ace89a53189..39f9495d532dd9ec42d2495e5e20103b79d38234 100644 (file)
@@ -29,7 +29,8 @@ static int cache_sanitycheck(struct phys_region *pr, char *file, int line);
 static int cache_writable(struct phys_region *pr);
 static int cache_resize(struct vmproc *vmp, struct vir_region *vr, vir_bytes l);
 static int cache_pagefault(struct vmproc *vmp, struct vir_region *region, 
-        struct phys_region *ph, int write, vfs_callback_t cb, void *, int);
+        struct phys_region *ph, int write, vfs_callback_t cb, void *state,
+       int len, int *io);
 
 struct mem_type mem_type_cache = {
        .name = "cache memory",
@@ -81,6 +82,7 @@ do_mapcache(message *msg)
        struct vir_region *vr;
        struct vmproc *caller;
        vir_bytes offset;
+       int io = 0;
 
        if(vm_isokendpt(msg->m_source, &n) != OK) panic("bogus source");
        caller = &vmproc[n];
@@ -113,7 +115,7 @@ do_mapcache(message *msg)
                assert(vr->length == bytes);
                assert(offset < vr->length);
 
-               if(map_pf(caller, vr, offset, 1, NULL, NULL, 0) != OK) {
+               if(map_pf(caller, vr, offset, 1, NULL, NULL, 0, &io) != OK) {
                        map_unmap_region(caller, vr, 0, bytes);
                        printf("VM: map_pf failed\n");
                        return ENOMEM;
@@ -136,7 +138,7 @@ do_mapcache(message *msg)
 
 static int cache_pagefault(struct vmproc *vmp, struct vir_region *region, 
         struct phys_region *ph, int write, vfs_callback_t cb,
-       void *state, int len)
+       void *state, int len, int *io)
 {
        vir_bytes offset = ph->offset;
        assert(ph->ph->phys == MAP_NONE);
index 740c6e4881dd9869f035a6a1b047e620b4b478fd..30638497525769d7c123a10d866bcf6c6ebdc17e 100644 (file)
@@ -17,7 +17,8 @@
 static int phys_unreference(struct phys_region *pr);
 static int phys_writable(struct phys_region *pr);
 static int phys_pagefault(struct vmproc *vmp, struct vir_region *region,
-        struct phys_region *ph, int write, vfs_callback_t cb, void *, int);
+        struct phys_region *ph, int write, vfs_callback_t cb, void *state,
+       int len, int *io);
 static int phys_copy(struct vir_region *vr, struct vir_region *newvr);
 
 struct mem_type mem_type_directphys = {
@@ -34,7 +35,8 @@ static int phys_unreference(struct phys_region *pr)
 }
 
 static int phys_pagefault(struct vmproc *vmp, struct vir_region *region,
-    struct phys_region *ph, int write, vfs_callback_t cb, void *st, int len)
+    struct phys_region *ph, int write, vfs_callback_t cb, void *state,
+    int len, int *io)
 {
        phys_bytes arg = region->param.phys, phmem;
        assert(arg != MAP_NONE);
index 93b5462258fb6a601d220d7c834a3fdd74907940..9fc51140da1af3b9f69253adcfc4ef9e9e37512f 100644 (file)
@@ -18,7 +18,8 @@ static void mappedfile_split(struct vmproc *vmp, struct vir_region *vr,
        struct vir_region *r1, struct vir_region *r2);
 static int mappedfile_unreference(struct phys_region *pr);
 static int mappedfile_pagefault(struct vmproc *vmp, struct vir_region *region, 
-       struct phys_region *ph, int write, vfs_callback_t callback, void *, int);
+       struct phys_region *ph, int write, vfs_callback_t callback, void *state,
+       int len, int *io);
 static int mappedfile_sanitycheck(struct phys_region *pr, char *file, int line);
 static int mappedfile_writable(struct phys_region *pr);
 static int mappedfile_copy(struct vir_region *vr, struct vir_region *newvr);
@@ -72,7 +73,7 @@ static int cow_block(struct vmproc *vmp, struct vir_region *region,
 
 static int mappedfile_pagefault(struct vmproc *vmp, struct vir_region *region,
        struct phys_region *ph, int write, vfs_callback_t cb,
-       void *state, int statelen)
+       void *state, int statelen, int *io)
 {
        u32_t allocflags;
        int procfd = region->param.file.fdref->fd;
@@ -123,7 +124,7 @@ static int mappedfile_pagefault(struct vmproc *vmp, struct vir_region *region,
                        printf("VM: mappedfile_pagefault: vfs_request failed\n");
                        return ENOMEM;
                }
-
+               *io = 1;
                return SUSPEND;
        }
 
index b7fdd49446935430b022e33a507cf0e63295329d..7a0f95fc12cfbb5a4c2ba4f7af2acaf235534bd7 100644 (file)
@@ -15,7 +15,8 @@
 
 static int shared_unreference(struct phys_region *pr);
 static int shared_pagefault(struct vmproc *vmp, struct vir_region *region, 
-       struct phys_region *ph, int write, vfs_callback_t cb, void *, int);
+       struct phys_region *ph, int write, vfs_callback_t cb, void *state,
+       int len, int *io);
 static int shared_sanitycheck(struct phys_region *pr, char *file, int line);
 static int shared_writable(struct phys_region *pr);
 static void shared_delete(struct vir_region *region);
@@ -110,7 +111,7 @@ static void shared_delete(struct vir_region *region)
 
 static int shared_pagefault(struct vmproc *vmp, struct vir_region *region,
        struct phys_region *ph, int write, vfs_callback_t cb,
-       void *state, int statelen)
+       void *state, int statelen, int *io)
 {
        struct vir_region *src_region;
        struct vmproc *src_vmp;
@@ -126,7 +127,7 @@ static int shared_pagefault(struct vmproc *vmp, struct vir_region *region,
        if(!(pr = physblock_get(src_region, ph->offset))) {
                int r;
                if((r=map_pf(src_vmp, src_region, ph->offset, write,
-                       NULL, NULL, 0)) != OK)
+                       NULL, NULL, 0, io)) != OK)
                        return r;
                if(!(pr = physblock_get(src_region, ph->offset))) {
                        panic("missing region after pagefault handling");
index 7ff4ce9c640b95a8c1dd039e39a2a70c9eae8fa7..f5ff38f006b8b3621960617560bd4d54e652d0a1 100644 (file)
@@ -16,7 +16,8 @@ typedef struct mem_type {
        int (*ev_reference)(struct phys_region *pr, struct phys_region *newpr);
        int (*ev_unreference)(struct phys_region *pr);
        int (*ev_pagefault)(struct vmproc *vmp, struct vir_region *region,
-        struct phys_region *ph, int write, vfs_callback_t cb, void *, int);
+        struct phys_region *ph, int write, vfs_callback_t cb, void *state,
+        int len, int *io);
        int (*ev_resize)(struct vmproc *vmp, struct vir_region *vr, vir_bytes len);
        void (*ev_split)(struct vmproc *vmp, struct vir_region *vr,
                struct vir_region *r1, struct vir_region *r2);
index c945f4857d7b4c4dd4b8484c1624b10403c6da01..ede0ad0fa65db295cf5fc237ae166715283aa5f3 100644 (file)
@@ -70,6 +70,7 @@ static void handle_pagefault(endpoint_t ep, vir_bytes addr, u32_t err, int retry
        struct vir_region *region;
        vir_bytes offset;
        int p, wr = PFERR_WRITE(err);
+       int io = 0;
 
        if(vm_isokendpt(ep, &p) != OK)
                panic("handle_pagefault: endpoint wrong: %d", ep);
@@ -111,7 +112,7 @@ static void handle_pagefault(endpoint_t ep, vir_bytes addr, u32_t err, int retry
 
        /* Access is allowed; handle it. */
        if(retry) {
-               result = map_pf(vmp, region, offset, wr, NULL, NULL, 0);
+               result = map_pf(vmp, region, offset, wr, NULL, NULL, 0, &io);
                assert(result != SUSPEND);
        } else {
                struct pf_state state;
@@ -119,8 +120,12 @@ static void handle_pagefault(endpoint_t ep, vir_bytes addr, u32_t err, int retry
                state.vaddr = addr;
                state.err = err;
                result = map_pf(vmp, region, offset, wr, pf_cont,
-                       &state, sizeof(state));
+                       &state, sizeof(state), &io);
        }
+       if (io)
+               vmp->vm_major_page_fault++;
+       else
+               vmp->vm_minor_page_fault++;
 
        if(result == SUSPEND) {
                return;
index f162045d2698883b6a29748a61c7b806d8d04b1a..5c98aa223e3709ea08a6b71b7c1357a640f659b5 100644 (file)
@@ -41,6 +41,7 @@ int get_stack_ptr(int proc_nr, vir_bytes *sp);
 int do_info(message *);
 int swap_proc_slot(struct vmproc *src_vmp, struct vmproc *dst_vmp);
 int swap_proc_dyn_data(struct vmproc *src_vmp, struct vmproc *dst_vmp);
+int do_getrusage(message *m);
 
 /* exit.c */
 void clear_proc(struct vmproc *vmp);
@@ -143,7 +144,8 @@ int map_proc_copy_from(struct vmproc *dst, struct vmproc *src, struct
 struct vir_region *map_lookup(struct vmproc *vmp, vir_bytes addr,
        struct phys_region **pr);
 int map_pf(struct vmproc *vmp, struct vir_region *region, vir_bytes
-       offset, int write, vfs_callback_t pf_callback, void *state, int);
+       offset, int write, vfs_callback_t pf_callback, void *state, int len,
+       int *io);
 int map_pin_memory(struct vmproc *vmp);
 int map_handle_memory(struct vmproc *vmp, struct vir_region *region,
        vir_bytes offset, vir_bytes len, int write, vfs_callback_t cb,
index 500056b9383bd0281adb4947895da43a4ffda2ef..8499c081257f1f1384ecab5ca82567b486b84082 100644 (file)
@@ -73,14 +73,21 @@ void physblock_set(struct vir_region *region, vir_bytes offset,
        struct phys_region *newphysr)
 {
        int i;
+       struct vmproc *proc;
        assert(!(offset % VM_PAGE_SIZE));
        assert(offset >= 0 && offset < region->length);
        i = offset/VM_PAGE_SIZE;
+       proc = region->parent;
+       assert(proc);
        if(newphysr) {
                assert(!region->physblocks[i]);
                assert(newphysr->offset == offset);
+               proc->vm_total += VM_PAGE_SIZE;
+               if (proc->vm_total > proc->vm_total_max)
+                       proc->vm_total_max = proc->vm_total;
        } else {
                assert(region->physblocks[i]);
+               proc->vm_total -= VM_PAGE_SIZE;
        }
        region->physblocks[i] = newphysr;
 }
@@ -671,7 +678,7 @@ u32_t vrallocflags(u32_t flags)
 /*===========================================================================*
  *                             map_pf                       *
  *===========================================================================*/
-int map_pf(vmp, region, offset, write, pf_callback, state, len)
+int map_pf(vmp, region, offset, write, pf_callback, state, len, io)
 struct vmproc *vmp;
 struct vir_region *region;
 vir_bytes offset;
@@ -679,6 +686,7 @@ int write;
 vfs_callback_t pf_callback;
 void *state;
 int len;
+int *io;
 {
        struct phys_region *ph;
        int r = OK;
@@ -725,7 +733,7 @@ int len;
                assert(ph->ph);
 
                if((r = ph->memtype->ev_pagefault(vmp,
-                       region, ph, write, pf_callback, state, len)) == SUSPEND) {
+                       region, ph, write, pf_callback, state, len, io)) == SUSPEND) {
                        return SUSPEND;
                }
 
@@ -774,6 +782,7 @@ int statelen;
 {
        vir_bytes offset, lim;
        int r;
+       int io = 0;
 
        assert(length > 0);
        lim = start_offset + length;
@@ -781,7 +790,7 @@ int statelen;
 
        for(offset = start_offset; offset < lim; offset += VM_PAGE_SIZE)
                if((r = map_pf(vmp, region, offset, write,
-                  cb, state, statelen)) != OK)
+                  cb, state, statelen, &io)) != OK)
                        return r;
 
        return OK;
index 87aad1c35fc64693ea2a8dd669478979f4476be2..eeb1fd9db7a774ee988ef25d91d9974867c1aca4 100644 (file)
@@ -23,6 +23,7 @@
 #include <assert.h>
 #include <sys/param.h>
 #include <sys/mman.h>
+#include <sys/resource.h>
 
 #include "proto.h"
 #include "glo.h"
@@ -320,4 +321,27 @@ int _brk(void *addr)
        return 0;
 }
 
+/*===========================================================================*
+ *                             do_getrusage                                 *
+ *===========================================================================*/
+int do_getrusage(message *m)
+{
+       int res, slot;
+       struct vmproc *vmp;
+       struct rusage r_usage;
+       if ((res = vm_isokendpt(m->m_source, &slot)) != OK)
+               return ESRCH;
 
+       vmp = &vmproc[slot];
+
+       if ((res = sys_datacopy(m->m_source, (vir_bytes) m->RU_RUSAGE_ADDR,
+               SELF, (vir_bytes) &r_usage, (vir_bytes) sizeof(r_usage))) < 0)
+               return res;
+
+       r_usage.ru_maxrss = vmp->vm_total_max;
+       r_usage.ru_minflt = vmp->vm_minor_page_fault;
+       r_usage.ru_majflt = vmp->vm_major_page_fault;
+
+       return sys_datacopy(SELF, &r_usage, m->m_source,
+               (vir_bytes) m->RU_RUSAGE_ADDR, (vir_bytes) sizeof(r_usage));
+}
index 5e7145505602d6ae6bf860e4f5340ccf71fa5737..f8c6e430a2f5ede30f80e1f4461dfa0c09700297 100644 (file)
@@ -25,6 +25,10 @@ struct vmproc {
 #if VMSTATS
        int vm_bytecopies;
 #endif
+       vir_bytes       vm_total;
+       vir_bytes       vm_total_max;
+       u64_t           vm_minor_page_fault;
+       u64_t           vm_major_page_fault;
 };
 
 /* Bits for vm_flags */
index e6fb8aebd41f11f7d6735e53e2e3f98a03a1ef5a..97b31185fa7821e0d0fe9e31bdf432390ca7a5d2 100644 (file)
 #define        PRIO_PGRP       1
 #define        PRIO_USER       2
 
+/*
+ * Resource utilization information.
+ */
+
+#define        RUSAGE_SELF     0
+#define        RUSAGE_CHILDREN -1
+
+struct rusage {
+       struct timeval ru_utime;        /* user time used */
+       struct timeval ru_stime;        /* system time used */
+       long    ru_maxrss;              /* max resident set size */
+#define        ru_first        ru_ixrss
+       long    ru_ixrss;               /* integral shared memory size */
+       long    ru_idrss;               /* integral unshared data " */
+       long    ru_isrss;               /* integral unshared stack " */
+       long    ru_minflt;              /* page reclaims */
+       long    ru_majflt;              /* page faults */
+       long    ru_nswap;               /* swaps */
+       long    ru_inblock;             /* block input operations */
+       long    ru_oublock;             /* block output operations */
+       long    ru_msgsnd;              /* messages sent */
+       long    ru_msgrcv;              /* messages received */
+       long    ru_nsignals;            /* signals received */
+       long    ru_nvcsw;               /* voluntary context switches */
+       long    ru_nivcsw;              /* involuntary " */
+#define        ru_last         ru_nivcsw
+};
+
 /*
  * Resource limits
  */
@@ -78,6 +106,7 @@ struct rlimit
 __BEGIN_DECLS
 int    getpriority(int, int);
 int    getrlimit(int, struct rlimit *);
+int    getrusage(int, struct rusage *);
 int    setpriority(int, int, int);
 __END_DECLS
 
index 58a1f7add14d4f556f7605fe854db9f724a7c700..af00c237b55f35d1c146a7ae0918f0dd24f647df 100644 (file)
@@ -49,7 +49,7 @@ MINIX_TESTS= \
  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 \
 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
 41 42 43 44 45 46    48 49 50    52 53 54 55 56    58 59 60 \
-61       64 65 66 67 68 69 70 71 72 73 74
+61       64 65 66 67 68 69 70 71 72 73 74 75
 
 .if ${MACHINE_ARCH} == "i386"
 MINIX_TESTS+= \
index fa6d2137688f679c98b14f09694d817c61f0abfb..ec0b821b03463a0de22015016f1961563176fcf3 100755 (executable)
--- a/test/run
+++ b/test/run
@@ -24,7 +24,7 @@ setuids="test11 test33 test43 test44 test46 test56 test60 test61 test65 \
 alltests="   1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 \
          21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
          41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 \
-         61 62 63 64 65 66 67 68 69 70 71 72 \
+         61 62 63 64 65 66 67 68 69 70 71 72 75 \
         sh1.sh sh2.sh interp.sh"
 tests_no=`expr 0`
 
diff --git a/test/test75.c b/test/test75.c
new file mode 100644 (file)
index 0000000..288d2a9
--- /dev/null
@@ -0,0 +1,114 @@
+/* Test 75 - getrusage functionality test.
+ */
+
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <stdio.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "common.h"
+
+#define CHECK_ZERO_FIELD(rusage, field)                \
+       if (rusage.field != 0)                  \
+               em(1, #field " must be zero");
+
+#define CHECK_NOT_ZERO_FIELD(rusage, field)    \
+       if (rusage.field == 0)                  \
+               em(1, #field " can't be zero");
+
+#define CHECK_EQUAL_FIELD(rusage1, rusage2, field)               \
+       if (rusage1.field != rusage2.field)                       \
+               em(1, #field " of " #rusage1 " doesn't equal to " \
+                       #field " of " #rusage2);
+
+static void spin()
+{
+       struct timeval start_time;
+       struct timeval end_time;
+       int loop = 0;
+       if (gettimeofday(&start_time, NULL) == -1) {
+               e(1);
+               exit(1);
+       }
+       memset(&end_time, 0, sizeof(end_time));
+       while (start_time.tv_sec + 10 > end_time.tv_sec) {
+               if ((++loop % 10000) == 0) {
+                       if (gettimeofday(&end_time, NULL) == -1) {
+                               e(1);
+                               exit(1);
+                       }
+               }
+       }
+}
+
+int
+main(int argc, char *argv[])
+{
+       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)) {
+               e(1);
+               exit(1);
+       }
+       spin();
+       if (getrusage(RUSAGE_SELF, &r_usage1) != 0) {
+               e(1);
+               exit(1);
+       }
+       CHECK_NOT_ZERO_FIELD(r_usage1, ru_utime.tv_sec);
+       CHECK_NOT_ZERO_FIELD(r_usage1, ru_maxrss);
+       CHECK_NOT_ZERO_FIELD(r_usage1, ru_ixrss);
+       CHECK_NOT_ZERO_FIELD(r_usage1, ru_idrss);
+       CHECK_NOT_ZERO_FIELD(r_usage1, ru_isrss);
+       if (getrusage(RUSAGE_CHILDREN, &r_usage2) != 0) {
+               e(1);
+               exit(1);
+       }
+       CHECK_ZERO_FIELD(r_usage2, ru_utime.tv_sec);
+       CHECK_ZERO_FIELD(r_usage2, ru_utime.tv_usec);
+       CHECK_NOT_ZERO_FIELD(r_usage2, ru_maxrss);
+       CHECK_NOT_ZERO_FIELD(r_usage2, ru_ixrss);
+       CHECK_NOT_ZERO_FIELD(r_usage2, ru_idrss);
+       CHECK_NOT_ZERO_FIELD(r_usage2, ru_isrss);
+       CHECK_EQUAL_FIELD(r_usage1, r_usage2, ru_ixrss);
+       CHECK_EQUAL_FIELD(r_usage1, r_usage2, ru_idrss);
+       CHECK_EQUAL_FIELD(r_usage1, r_usage2, ru_isrss);
+       if ((child = fork()) != 0) {
+               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);
+               }
+               CHECK_NOT_ZERO_FIELD(r_usage3, ru_utime.tv_sec);
+               CHECK_NOT_ZERO_FIELD(r_usage3, ru_maxrss);
+               CHECK_NOT_ZERO_FIELD(r_usage3, ru_ixrss);
+               CHECK_NOT_ZERO_FIELD(r_usage3, ru_idrss);
+               CHECK_NOT_ZERO_FIELD(r_usage3, ru_isrss);
+               CHECK_EQUAL_FIELD(r_usage1, r_usage3, ru_ixrss);
+               CHECK_EQUAL_FIELD(r_usage1, r_usage3, ru_idrss);
+               CHECK_EQUAL_FIELD(r_usage1, r_usage3, ru_isrss);
+       } else {
+               spin();
+               exit(0);
+       }
+       quit();
+
+       return 0;
+}