diff --git a/distrib/sets/lists/minix/mi b/distrib/sets/lists/minix/mi index ce34f47dc..8701b038d 100644 --- a/distrib/sets/lists/minix/mi +++ b/distrib/sets/lists/minix/mi @@ -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 diff --git a/include/minix/callnr.h b/include/minix/callnr.h index 0ec74931b..629f04ec2 100644 --- a/include/minix/callnr.h +++ b/include/minix/callnr.h @@ -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 */ diff --git a/include/minix/com.h b/include/minix/com.h index 08496d220..59bab8112 100644 --- a/include/minix/com.h +++ b/include/minix/com.h @@ -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 */ diff --git a/include/minix/syslib.h b/include/minix/syslib.h index a5fcefc6f..863790091 100644 --- a/include/minix/syslib.h +++ b/include/minix/syslib.h @@ -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 diff --git a/kernel/proc.c b/kernel/proc.c index 6dcaf9125..140ac4724 100644 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -1906,3 +1906,8 @@ void ser_dump_proc() print_proc_recursive(pp); } } + +void increase_proc_signals(struct proc *p) +{ + p->p_signal_received++; +} diff --git a/kernel/proc.h b/kernel/proc.h index 439396937..2f749b5c7 100644 --- a/kernel/proc.h +++ b/kernel/proc.h @@ -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 diff --git a/kernel/proto.h b/kernel/proto.h index 7952922dd..ed382c7b9 100644 --- a/kernel/proto.h +++ b/kernel/proto.h @@ -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); diff --git a/kernel/system.c b/kernel/system.c index caafd9943..423b353b1 100644 --- a/kernel/system.c +++ b/kernel/system.c @@ -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)) diff --git a/kernel/system/do_fork.c b/kernel/system/do_fork.c index f30927025..c58622102 100644 --- a/kernel/system/do_fork.c +++ b/kernel/system/do_fork.c @@ -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. diff --git a/kernel/system/do_getinfo.c b/kernel/system/do_getinfo.c index 19ab73c14..fef7ce5a4 100644 --- a/kernel/system/do_getinfo.c +++ b/kernel/system/do_getinfo.c @@ -17,6 +17,7 @@ #if USE_GETINFO #include +#include /*===========================================================================* * 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); diff --git a/lib/libc/sys-minix/Makefile.inc b/lib/libc/sys-minix/Makefile.inc index 98a208fab..890b66d87 100644 --- a/lib/libc/sys-minix/Makefile.inc +++ b/lib/libc/sys-minix/Makefile.inc @@ -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 index 000000000..271eb241b --- /dev/null +++ b/lib/libc/sys-minix/getrusage.c @@ -0,0 +1,32 @@ +#include +#include "namespace.h" +#include + +#include +#include + +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); +} diff --git a/lib/libc/sys/Makefile.inc b/lib/libc/sys/Makefile.inc index b20b7ea66..2fa88dfd5 100644 --- a/lib/libc/sys/Makefile.inc +++ b/lib/libc/sys/Makefile.inc @@ -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 \ diff --git a/lib/libexec/exec_elf.c b/lib/libexec/exec_elf.c index 06c1bfd7d..131f6deb2 100644 --- a/lib/libexec/exec_elf.c +++ b/lib/libexec/exec_elf.c @@ -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", diff --git a/lib/libexec/libexec.h b/lib/libexec/libexec.h index 8597e74c3..b9a8fe15f 100644 --- a/lib/libexec/libexec.h +++ b/lib/libexec/libexec.h @@ -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 */ diff --git a/servers/pm/misc.c b/servers/pm/misc.c index c3a198b39..0576a5513 100644 --- a/servers/pm/misc.c +++ b/servers/pm/misc.c @@ -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)); +} diff --git a/servers/pm/proto.h b/servers/pm/proto.h index 73e8a4a69..0dc30709f 100644 --- a/servers/pm/proto.h +++ b/servers/pm/proto.h @@ -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); diff --git a/servers/pm/table.c b/servers/pm/table.c index d1c2075a1..b9007553b 100644 --- a/servers/pm/table.c +++ b/servers/pm/table.c @@ -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]; diff --git a/servers/vfs/exec.c b/servers/vfs/exec.c index 8a58a77ee..c0bbe58ae 100644 --- a/servers/vfs/exec.c +++ b/servers/vfs/exec.c @@ -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); diff --git a/servers/vfs/fproc.h b/servers/vfs/fproc.h index 9ef7acbd0..3f9ff28e9 100644 --- a/servers/vfs/fproc.h +++ b/servers/vfs/fproc.h @@ -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 */ diff --git a/servers/vfs/misc.c b/servers/vfs/misc.c index 6d9a7269e..7f8dede77 100644 --- a/servers/vfs/misc.c +++ b/servers/vfs/misc.c @@ -30,6 +30,7 @@ #include #include #include +#include #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)); +} diff --git a/servers/vfs/proto.h b/servers/vfs/proto.h index 339949042..6a048c25d 100644 --- a/servers/vfs/proto.h +++ b/servers/vfs/proto.h @@ -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); diff --git a/servers/vfs/table.c b/servers/vfs/table.c index 6aa4f734b..586c055d5 100644 --- a/servers/vfs/table.c +++ b/servers/vfs/table.c @@ -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]; diff --git a/servers/vm/exit.c b/servers/vm/exit.c index f287b327a..11cfcc94b 100644 --- a/servers/vm/exit.c +++ b/servers/vm/exit.c @@ -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); } /*===========================================================================* diff --git a/servers/vm/main.c b/servers/vm/main.c index 3f494033a..95e64486d 100644 --- a/servers/vm/main.c +++ b/servers/vm/main.c @@ -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(); diff --git a/servers/vm/mem_anon.c b/servers/vm/mem_anon.c index 9adc52419..5158f882d 100644 --- a/servers/vm/mem_anon.c +++ b/servers/vm/mem_anon.c @@ -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; diff --git a/servers/vm/mem_anon_contig.c b/servers/vm/mem_anon_contig.c index 1f2750d18..127ee4cfa 100644 --- a/servers/vm/mem_anon_contig.c +++ b/servers/vm/mem_anon_contig.c @@ -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"); } diff --git a/servers/vm/mem_cache.c b/servers/vm/mem_cache.c index 7bc0bc24e..39f9495d5 100644 --- a/servers/vm/mem_cache.c +++ b/servers/vm/mem_cache.c @@ -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); diff --git a/servers/vm/mem_directphys.c b/servers/vm/mem_directphys.c index 740c6e488..306384975 100644 --- a/servers/vm/mem_directphys.c +++ b/servers/vm/mem_directphys.c @@ -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); diff --git a/servers/vm/mem_file.c b/servers/vm/mem_file.c index 93b546225..9fc51140d 100644 --- a/servers/vm/mem_file.c +++ b/servers/vm/mem_file.c @@ -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; } diff --git a/servers/vm/mem_shared.c b/servers/vm/mem_shared.c index b7fdd4944..7a0f95fc1 100644 --- a/servers/vm/mem_shared.c +++ b/servers/vm/mem_shared.c @@ -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"); diff --git a/servers/vm/memtype.h b/servers/vm/memtype.h index 7ff4ce9c6..f5ff38f00 100644 --- a/servers/vm/memtype.h +++ b/servers/vm/memtype.h @@ -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); diff --git a/servers/vm/pagefaults.c b/servers/vm/pagefaults.c index c945f4857..ede0ad0fa 100644 --- a/servers/vm/pagefaults.c +++ b/servers/vm/pagefaults.c @@ -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; diff --git a/servers/vm/proto.h b/servers/vm/proto.h index f162045d2..5c98aa223 100644 --- a/servers/vm/proto.h +++ b/servers/vm/proto.h @@ -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, diff --git a/servers/vm/region.c b/servers/vm/region.c index 500056b93..8499c0812 100644 --- a/servers/vm/region.c +++ b/servers/vm/region.c @@ -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; diff --git a/servers/vm/utility.c b/servers/vm/utility.c index 87aad1c35..eeb1fd9db 100644 --- a/servers/vm/utility.c +++ b/servers/vm/utility.c @@ -23,6 +23,7 @@ #include #include #include +#include #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)); +} diff --git a/servers/vm/vmproc.h b/servers/vm/vmproc.h index 5e7145505..f8c6e430a 100644 --- a/servers/vm/vmproc.h +++ b/servers/vm/vmproc.h @@ -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 */ diff --git a/sys/sys/resource.h b/sys/sys/resource.h index e6fb8aebd..97b31185f 100644 --- a/sys/sys/resource.h +++ b/sys/sys/resource.h @@ -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 diff --git a/test/Makefile b/test/Makefile index 58a1f7add..af00c237b 100644 --- a/test/Makefile +++ b/test/Makefile @@ -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+= \ diff --git a/test/run b/test/run index fa6d21376..ec0b821b0 100755 --- 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 index 000000000..288d2a98d --- /dev/null +++ b/test/test75.c @@ -0,0 +1,114 @@ +/* Test 75 - getrusage functionality test. + */ + +#include +#include +#include +#include +#include +#include +#include + +#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; +}