On Thu, Oct 17, 2019 at 05:55:20AM -0600, Todd C. Miller wrote:
> On Wed, 16 Oct 2019 10:23:52 -0500, Scott Cheloha wrote:
> 
> > Tracking the process starting time as an uptime fixes the classic
> > "init(8) started in 1969" bug in ps(1) when your CMOS battery dies.
> >
> > In general it lets us track how long a process has been running
> > correctly regardless of whether or not the kernel UTC clock has
> > jumped.
> 
> One comment inline.
> 
> > NetBSD and FreeBSD have already done this.
> >
> > For kernel core dumps we need to do a bit of shuffling in libkvm to
> > determine the approximate starting time.  The granularity is much more
> > limited in this case, but it's a start.
> >
> > I have added nanoboottime(9) here because it simplifies the math
> > in kern_acct.c.  I can commit that first in a separate patch.
> >
> > ok?
> >
> > Index: sys/kern/kern_sysctl.c
> > ===================================================================
> > RCS file: /cvs/src/sys/kern/kern_sysctl.c,v
> > retrieving revision 1.366
> > diff -u -p -r1.366 kern_sysctl.c
> > --- sys/kern/kern_sysctl.c  21 Aug 2019 20:44:09 -0000      1.366
> > +++ sys/kern/kern_sysctl.c  16 Oct 2019 15:15:31 -0000
> > @@ -1637,7 +1637,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 st, ut;
> > +   struct timeval booted, starting_uptime, starting_utc;
> >     int isthread;
> >  
> >     isthread = p != NULL;
> > @@ -1679,6 +1680,13 @@ fill_kproc(struct process *pr, struct ki
> >                     ki->p_cpuid = CPU_INFO_UNIT(p->p_cpu);
> >  #endif
> >     }
> > +
> > +   /* Convert starting uptime to a starting UTC time. */
> > +   TIMESPEC_TO_TIMEVAL(&starting_uptime, &pr->ps_start);
> > +   microboottime(&booted);
> > +   timeradd(&booted, &starting_uptime, &starting_utc);
> > +   ki->p_ustart_sec = starting_utc.tv_sec;
> > +   ki->p_ustart_usec = starting_utc.tv_usec;
> 
> FILL_KPROC only fills in p_ustart_sec and p_ustart_usec for non-zombie
> processes.  You probably want to do the same.  You are also missing
> a diff to sys/sysctl.h to remove p_ustart_sec and p_ustart_usec from
> FILL_KPROC.

Any reason we don't update those fields for zombies?  Are they really
never interesting after the process has exited or died?

> >     /* get %cpu and schedule state: just one thread or sum of all? */
> >     if (isthread) {
> 
> The rest looks fine, modulo the nlist issue bluhm@ noticed.

Updated diff below.

Index: sys/kern/kern_sysctl.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_sysctl.c,v
retrieving revision 1.366
diff -u -p -r1.366 kern_sysctl.c
--- sys/kern/kern_sysctl.c      21 Aug 2019 20:44:09 -0000      1.366
+++ sys/kern/kern_sysctl.c      21 Oct 2019 17:14:06 -0000
@@ -1637,7 +1637,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 st, ut;
+       struct timeval booted, starting_uptime, starting_utc;
        int isthread;
 
        isthread = p != NULL;
@@ -1673,6 +1674,13 @@ fill_kproc(struct process *pr, struct ki
                ki->p_uutime_usec = ut.tv_nsec/1000;
                ki->p_ustime_sec = st.tv_sec;
                ki->p_ustime_usec = st.tv_nsec/1000;
+
+               /* Convert starting uptime to a starting UTC time. */
+               TIMESPEC_TO_TIMEVAL(&starting_uptime, &pr->ps_start);
+               microboottime(&booted);
+               timeradd(&booted, &starting_uptime, &starting_utc);
+               ki->p_ustart_sec = starting_utc.tv_sec;
+               ki->p_ustart_usec = starting_utc.tv_usec;
 
 #ifdef MULTIPROCESSOR
                if (p->p_cpu != NULL)
Index: sys/kern/kern_acct.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_acct.c,v
retrieving revision 1.41
diff -u -p -r1.41 kern_acct.c
--- sys/kern/kern_acct.c        6 Oct 2019 16:24:14 -0000       1.41
+++ sys/kern/kern_acct.c        21 Oct 2019 17:14:06 -0000
@@ -171,7 +171,7 @@ acct_process(struct proc *p)
        struct acct acct;
        struct process *pr = p->p_p;
        struct rusage *r;
-       struct timespec ut, st, tmp;
+       struct timespec booted, elapsed, realstart, uptime, ut, st, tmp;
        int t;
        struct vnode *vp;
        int error = 0;
@@ -203,10 +203,12 @@ 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);
-       timespecsub(&tmp, &pr->ps_start, &tmp);
-       acct.ac_etime = encode_comp_t(tmp.tv_sec, tmp.tv_nsec);
+       nanouptime(&uptime);
+       nanoboottime(&booted);
+       timespecadd(&booted, &uptime, &realstart);
+       acct.ac_btime = realstart.tv_sec;
+       timespecsub(&uptime, &pr->ps_start, &elapsed);
+       acct.ac_etime = encode_comp_t(elapsed.tv_sec, elapsed.tv_nsec);
 
        /* (4) The average amount of memory used */
        r = &p->p_ru;
Index: sys/kern/kern_fork.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_fork.c,v
retrieving revision 1.215
diff -u -p -r1.215 kern_fork.c
--- sys/kern/kern_fork.c        21 Oct 2019 10:24:01 -0000      1.215
+++ sys/kern/kern_fork.c        21 Oct 2019 17:14:06 -0000
@@ -462,7 +462,7 @@ fork1(struct proc *curp, int flags, void
        /*
         * For new processes, set accounting bits and mark as complete.
         */
-       getnanotime(&pr->ps_start);
+       nanouptime(&pr->ps_start);
        pr->ps_acflag = AFORK;
        atomic_clearbits_int(&pr->ps_flags, PS_EMBRYO);
 
Index: sys/kern/init_main.c
===================================================================
RCS file: /cvs/src/sys/kern/init_main.c,v
retrieving revision 1.290
diff -u -p -r1.290 init_main.c
--- sys/kern/init_main.c        21 Jun 2019 09:39:48 -0000      1.290
+++ sys/kern/init_main.c        21 Oct 2019 17:14:06 -0000
@@ -517,7 +517,7 @@ main(void *framep)
         * munched in mi_switch() after the time got set.
         */
        LIST_FOREACH(pr, &allprocess, ps_list) {
-               getnanotime(&pr->ps_start);
+               nanouptime(&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_tc.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_tc.c,v
retrieving revision 1.48
diff -u -p -r1.48 kern_tc.c
--- sys/kern/kern_tc.c  3 Jun 2019 01:27:30 -0000       1.48
+++ sys/kern/kern_tc.c  21 Oct 2019 17:14:06 -0000
@@ -167,6 +167,15 @@ microboottime(struct timeval *tvp)
 }
 
 void
+nanoboottime(struct timespec *tsp)
+{
+       struct bintime bt;
+       
+       binboottime(&bt);
+       BINTIME_TO_TIMESPEC(&bt, tsp);
+}
+
+void
 binuptime(struct bintime *bt)
 {
        struct timehands *th;
Index: lib/libkvm/kvm_proc2.c
===================================================================
RCS file: /cvs/src/lib/libkvm/kvm_proc2.c,v
retrieving revision 1.29
diff -u -p -r1.29 kvm_proc2.c
--- lib/libkvm/kvm_proc2.c      23 Jun 2019 16:57:02 -0000      1.29
+++ lib/libkvm/kvm_proc2.c      21 Oct 2019 17:14:06 -0000
@@ -117,16 +117,40 @@ kvm_proclist(kvm_t *kd, int op, int arg,
        struct process process, process2;
        struct pgrp pgrp;
        struct tty tty;
+       struct timeval elapsed, monostart, monostop, realstart, realstop;
+       struct nlist nl[3];
        struct sigacts sa, *sap;
        struct vmspace vm, *vmp;
        struct plimit limits, *limp;
        pid_t parent_pid, leader_pid;
        int cnt = 0;
        int dothreads = 0;
+       int i;
 
        dothreads = op & KERN_PROC_SHOW_THREADS;
        op &= ~KERN_PROC_SHOW_THREADS;
 
+       /* Anchor a time to compare process starting times from. */
+       nl[0].n_name = "_time_second";
+       nl[1].n_name = "_time_uptime";
+       nl[2].n_name = NULL;
+       if (kvm_nlist(kd, nl) != 0) {
+               for (i = 0; nl[i].n_type != 0; ++i)
+                       continue;
+               _kvm_err(kd, kd->program, "%s: no such symbol", nl[i].n_name);
+               return (-1);
+       }
+       timerclear(&realstop);
+       timerclear(&monostop);
+       if (KREAD(kd, nl[0].n_value, &realstop.tv_sec)) {
+               _kvm_err(kd, kd->program, "cannot read time_second");
+               return (-1);
+       }
+       if (KREAD(kd, nl[1].n_value, &monostop.tv_sec)) {
+               _kvm_err(kd, kd->program, "cannot read time_uptime");
+               return (-1);
+       }
+
        /*
         * Modelled on sysctl_doproc() in sys/kern/kern_sysctl.c
         */
@@ -288,6 +312,18 @@ kvm_proclist(kvm_t *kd, int op, int arg,
                } else {
                        kp.p_tpgid = -1;
                        kp.p_tdev = NODEV;
+               }
+
+               /* Convert the starting uptime to a starting UTC time. */
+               if ((process.ps_flags & PS_ZOMBIE) == 0) {
+                       monostart.tv_sec = kp.p_ustart_sec;
+                       monostart.tv_usec = kp.p_ustart_usec;
+                       timersub(&monostop, &monostart, &elapsed);
+                       if (elapsed.tv_sec < 0)
+                               timerclear(&elapsed);
+                       timersub(&realstop, &elapsed, &realstart);
+                       kp.p_ustart_sec = realstart.tv_sec;
+                       kp.p_ustart_usec = realstart.tv_usec;
                }
 
                /* update %cpu for all threads */
Index: sys/sys/proc.h
===================================================================
RCS file: /cvs/src/sys/sys/proc.h,v
retrieving revision 1.274
diff -u -p -r1.274 proc.h
--- sys/sys/proc.h      21 Oct 2019 10:24:01 -0000      1.274
+++ sys/sys/proc.h      21 Oct 2019 17:14:06 -0000
@@ -260,7 +260,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 uptime. */
        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.195
diff -u -p -r1.195 sysctl.h
--- sys/sys/sysctl.h    21 Aug 2019 20:44:09 -0000      1.195
+++ sys/sys/sysctl.h    21 Oct 2019 17:14:06 -0000
@@ -670,9 +670,6 @@ do {                                                        
                \
                                                                        \
                (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;                 \
                (kp)->p_uru_idrss = (p)->p_ru.ru_idrss;                 \
Index: sys/sys/time.h
===================================================================
RCS file: /cvs/src/sys/sys/time.h,v
retrieving revision 1.46
diff -u -p -r1.46 time.h
--- sys/sys/time.h      3 Aug 2019 22:53:45 -0000       1.46
+++ sys/sys/time.h      21 Oct 2019 17:14:06 -0000
@@ -293,6 +293,7 @@ void        getmicrouptime(struct timeval *);
 
 void   binboottime(struct bintime *);
 void   microboottime(struct timeval *);
+void   nanoboottime(struct timespec *);
 
 struct proc;
 int    clock_gettime(struct proc *, clockid_t, struct timespec *);
Index: share/man/man9/microtime.9
===================================================================
RCS file: /cvs/src/share/man/man9/microtime.9,v
retrieving revision 1.18
diff -u -p -r1.18 microtime.9
--- share/man/man9/microtime.9  19 Jan 2019 01:53:44 -0000      1.18
+++ share/man/man9/microtime.9  21 Oct 2019 17:14:06 -0000
@@ -41,6 +41,7 @@
 .Nm getnanotime ,
 .Nm nanouptime ,
 .Nm getnanouptime ,
+.Nm nanoboottime ,
 .Nm bintime ,
 .Nm binuptime ,
 .Nm binboottime
@@ -81,6 +82,10 @@
 .Fc
 .Ft void
 .Fo getnanouptime
+.Fa "struct timespec *tv"
+.Fc
+.Ft void
+.Fo nanoboottime
 .Fa "struct timespec *tv"
 .Fc
 .Ft void

Reply via email to