Hi, Because the system clock can jump around, process start times should be recorded as offsets from boot and only converted to a time of day on request.
This keeps ps(1)'s etime accurate and ensures processes are correctly sorted by age in ps(1) and pgrep(1). I don't think we're losing much by declining to preserve the time of day when the process forked. FreeBSD has made this change, though NetBSD has not. The attached patch isn't perfect, as there remains a small window after kvm_getprocs is called where the system clock can jump again. To circumvent that we'd need to compute the elapsed real time for the process in the kernel, or pass out ps_start alongside the derived time of day and let userspace compute the elapsed realtime with the CLOCK_BOOTTIME clock. Unsure how people feel about extending kinfo_proc, though. This change doesn't require any userspace recompilation for inspecting a live kernel: on reboot -lkvm binaries behave as expected. I'm pretty sure this will require changes to libkvm to fix up the start time when inspecting a dead kernel, but I can't figure out how to core my own system so I can test said changes. Thoughts? Help creating a core for test? -- Scott Cheloha Index: sys/kern/init_main.c =================================================================== RCS file: /cvs/src/sys/kern/init_main.c,v retrieving revision 1.277 diff -u -p -r1.277 init_main.c --- sys/kern/init_main.c 28 Apr 2018 03:13:04 -0000 1.277 +++ sys/kern/init_main.c 5 Jun 2018 16:43:08 -0000 @@ -512,7 +512,7 @@ main(void *framep) */ nanotime(&boottime); LIST_FOREACH(pr, &allprocess, ps_list) { - pr->ps_start = boottime; + getnanouptime(&pr->ps_start); TAILQ_FOREACH(p, &pr->ps_threads, p_thr_link) { nanouptime(&p->p_cpu->ci_schedstate.spc_runtime); timespecclear(&p->p_rtime); Index: sys/kern/kern_acct.c =================================================================== RCS file: /cvs/src/sys/kern/kern_acct.c,v retrieving revision 1.36 diff -u -p -r1.36 kern_acct.c --- sys/kern/kern_acct.c 28 Apr 2018 03:13:04 -0000 1.36 +++ sys/kern/kern_acct.c 5 Jun 2018 16:43:08 -0000 @@ -184,8 +184,8 @@ acct_process(struct proc *p) acct.ac_stime = encode_comp_t(st.tv_sec, st.tv_nsec); /* (3) The elapsed time the command ran (and its starting time) */ - acct.ac_btime = pr->ps_start.tv_sec; - getnanotime(&tmp); + getnanouptime(&tmp); + acct.ac_btime = time_second - (tmp.tv_sec - pr->ps_start.tv_sec); timespecsub(&tmp, &pr->ps_start, &tmp); acct.ac_etime = encode_comp_t(tmp.tv_sec, tmp.tv_nsec); Index: sys/kern/kern_fork.c =================================================================== RCS file: /cvs/src/sys/kern/kern_fork.c,v retrieving revision 1.202 diff -u -p -r1.202 kern_fork.c --- sys/kern/kern_fork.c 30 Dec 2017 20:47:00 -0000 1.202 +++ sys/kern/kern_fork.c 5 Jun 2018 16:43:08 -0000 @@ -451,7 +451,7 @@ fork1(struct proc *curp, int flags, void /* * For new processes, set accounting bits and mark as complete. */ - getnanotime(&pr->ps_start); + getnanouptime(&pr->ps_start); pr->ps_acflag = AFORK; atomic_clearbits_int(&pr->ps_flags, PS_EMBRYO); Index: sys/kern/kern_sysctl.c =================================================================== RCS file: /cvs/src/sys/kern/kern_sysctl.c,v retrieving revision 1.341 diff -u -p -r1.341 kern_sysctl.c --- sys/kern/kern_sysctl.c 2 Jun 2018 16:38:21 -0000 1.341 +++ sys/kern/kern_sysctl.c 5 Jun 2018 16:43:08 -0000 @@ -1596,7 +1596,8 @@ fill_kproc(struct process *pr, struct ki struct session *s = pr->ps_session; struct tty *tp; struct vmspace *vm = pr->ps_vmspace; - struct timespec ut, st; + struct timespec elapsed, now, started, uptime; + struct timespec st, ut; int isthread; isthread = p != NULL; @@ -1627,6 +1628,12 @@ fill_kproc(struct process *pr, struct ki if ((pr->ps_flags & PS_ZOMBIE) == 0) { if ((pr->ps_flags & PS_EMBRYO) == 0 && vm != NULL) ki->p_vm_rssize = vm_resident_count(vm); + getnanouptime(&uptime); + getnanotime(&now); + timespecsub(&uptime, &pr->ps_start, &elapsed); + timespecsub(&now, &elapsed, &started); + ki->p_ustart_sec = started.tv_sec; + ki->p_ustart_usec = started.tv_nsec/1000; calctsru(isthread ? &p->p_tu : &pr->ps_tu, &ut, &st, NULL); ki->p_uutime_sec = ut.tv_sec; ki->p_uutime_usec = ut.tv_nsec/1000; Index: sys/sys/proc.h =================================================================== RCS file: /cvs/src/sys/sys/proc.h,v retrieving revision 1.248 diff -u -p -r1.248 proc.h --- sys/sys/proc.h 12 Apr 2018 17:13:44 -0000 1.248 +++ sys/sys/proc.h 5 Jun 2018 16:43:08 -0000 @@ -228,7 +228,7 @@ struct process { #define ps_endcopy ps_refcnt int ps_refcnt; /* Number of references. */ - struct timespec ps_start; /* starting time. */ + struct timespec ps_start; /* starting boot offset. */ struct timeout ps_realit_to; /* real-time itimer trampoline. */ }; Index: sys/sys/sysctl.h =================================================================== RCS file: /cvs/src/sys/sys/sysctl.h,v retrieving revision 1.177 diff -u -p -r1.177 sysctl.h --- sys/sys/sysctl.h 26 May 2018 10:16:14 -0000 1.177 +++ sys/sys/sysctl.h 5 Jun 2018 16:43:08 -0000 @@ -516,7 +516,8 @@ struct kinfo_vmentry { * sa - source struct sigacts * There are some members that are not handled by these macros * because they're too painful to generalize: p_ppid, p_sid, p_tdev, - * p_tpgid, p_tsess, p_vm_rssize, p_u[us]time_{sec,usec}, p_cpuid + * p_tpgid, p_tsess, p_vm_rssize, p_u[us]time_{sec,usec}, p_cpuid, + * p_ustart_{sec,usec} */ #define PTRTOINT64(_x) ((u_int64_t)(u_long)(_x)) @@ -629,9 +630,6 @@ do { \ struct timeval tv; \ \ (kp)->p_uvalid = 1; \ - \ - (kp)->p_ustart_sec = (pr)->ps_start.tv_sec; \ - (kp)->p_ustart_usec = (pr)->ps_start.tv_nsec/1000; \ \ (kp)->p_uru_maxrss = (p)->p_ru.ru_maxrss; \ (kp)->p_uru_ixrss = (p)->p_ru.ru_ixrss; \