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
./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
-#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 */
# 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 */
/* Forward declaration */
struct reg86u;
struct rs_pci;
+struct rusage;
#define SYSTASK SYSTEM
#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
print_proc_recursive(pp);
}
}
+
+void increase_proc_signals(struct proc *p)
+{
+ p->p_signal_received++;
+}
*/
struct { reg_t r1, r2, r3; } p_defer;
+ u64_t p_signal_received;
+
#if DEBUG_TRACE
int p_schedules;
#endif
#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);
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;
/* 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))
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.
#if USE_GETINFO
#include <minix/u64.h>
+#include <sys/resource.h>
/*===========================================================================*
* update_idle_time *
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) {
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);
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
--- /dev/null
+#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);
+}
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 \
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 \
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",
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 */
_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));
+}
int do_getepinfo_o(void);
int do_svrctl(void);
int do_getsetpriority(void);
+int do_getrusage(void);
/* schedule.c */
void sched_init(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];
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);
/* 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);
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 */
#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"
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));
+}
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);
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];
#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);
vmp->vm_bytecopies = 0;
#endif
vmp->vm_region_top = 0;
+ reset_vm_rusage(vmp);
}
void clear_proc(struct vmproc *vmp)
vmp->vm_bytecopies = 0;
#endif
vmp->vm_region_top = 0;
+ reset_vm_rusage(vmp);
}
/*===========================================================================*
CALLMAP(VM_MAPCACHEPAGE, do_mapcache);
CALLMAP(VM_SETCACHEPAGE, do_setcache);
+ /* getrusage */
+ CALLMAP(VM_GETRUSAGE, do_getrusage);
+
/* Initialize the structures for queryexit */
init_query_exit();
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);
}
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;
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);
};
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");
}
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",
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];
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;
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);
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 = {
}
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);
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);
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;
printf("VM: mappedfile_pagefault: vfs_request failed\n");
return ENOMEM;
}
-
+ *io = 1;
return SUSPEND;
}
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);
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;
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");
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);
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);
/* 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;
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;
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);
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,
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;
}
/*===========================================================================*
* 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;
vfs_callback_t pf_callback;
void *state;
int len;
+int *io;
{
struct phys_region *ph;
int r = OK;
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;
}
{
vir_bytes offset, lim;
int r;
+ int io = 0;
assert(length > 0);
lim = start_offset + length;
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;
#include <assert.h>
#include <sys/param.h>
#include <sys/mman.h>
+#include <sys/resource.h>
#include "proto.h"
#include "glo.h"
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));
+}
#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 */
#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
*/
__BEGIN_DECLS
int getpriority(int, int);
int getrlimit(int, struct rlimit *);
+int getrusage(int, struct rusage *);
int setpriority(int, int, int);
__END_DECLS
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+= \
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`
--- /dev/null
+/* 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;
+}