Implement getrusage

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
This commit is contained in:
Xiaoguang Sun 2013-06-25 20:41:01 +08:00 committed by Gerrit Code Review
parent 4241cc5d98
commit 64f10ee644
41 changed files with 403 additions and 29 deletions

View file

@ -1508,6 +1508,7 @@
./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
@ -4653,6 +4654,7 @@
./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

View 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
@ -113,3 +113,4 @@
* really a standalone call.
*/
#define MAPDRIVER 122 /* to VFS, map a device */
#define GETRUSAGE 123 /* to PM, VFS */

View file

@ -473,6 +473,7 @@
# 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 */
@ -1078,8 +1079,10 @@
#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 */
@ -1294,4 +1297,9 @@
# 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 */

View 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

View file

@ -1906,3 +1906,8 @@ void ser_dump_proc()
print_proc_recursive(pp);
}
}
void increase_proc_signals(struct proc *p)
{
p->p_signal_received++;
}

View 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

View 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);

View 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))

View 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.

View 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);

View 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

View file

@ -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);
}

View 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 \

View 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",

View 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 */

View 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));
}

View 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);

View 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];

View 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);

View 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 */

View 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));
}

View 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);

View 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];

View file

@ -24,6 +24,14 @@
#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);
}
/*===========================================================================*

View 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();

View 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;

View 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");
}

View 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);

View 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);

View 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;
}

View 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");

View 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);

View 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;

View 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,

View 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;

View 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));
}

View 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 */

View file

@ -47,6 +47,34 @@
#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

View 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+= \

View file

@ -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`

114
test/test75.c Normal file
View file

@ -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;
}