Hi,

The code in realitexpire(), the ITIMER_REAL timeout callback, is
needlessly complicated.

kn@ wanted to clean it up a while ago but I wan't far enough along
with hi-res timeouts to change the code yet.

Hi-res timeouts are now imminent, and setitimer(2) will probably be
the first guinnea pig I use to demonstrate that they Actually Work.
This cleanup will make employing a hi-res timeout here in a later diff
a lot simpler.

So, the cleanup:

- No need to call getnanouptime(9) more than once.  timespecadd(3) is
  very fast, and it_interval is at least 1/hz seconds wide, so we expect
  to "catch up" to the uptime after a couple iterations at most.

  When we switch to a hi-res timeout this will be important.  We will
  need to switch to nanouptime(9), which is much more expensive than
  getnanouptime(9).

- The for-loop and indentation here is really peculiar.  Use a while-loop
  to increment it_value and pull the rest of the code out of the loop.

- Collapse intermediate assignments.  tstohz(9) cannot return 0 in
  this case as it_interval is non-zero, so the check for timo < 0 is
  pointless.  With that out of the way, all we want to do is round
  back up to 1 if (tstohz(9) - 1 == 0), which we can do with MAX().

I am leaving the PS_EXITING check in place.  I am *pretty* sure it is
superfluous: realitexpire() runs under the kernel lock, and _exit(2)
runs under the kernel lock, so we aren't racing _exit(2)... but I will
leave it in-place until I can confirm my suspicions with the right
people.

ok?

Index: kern_time.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_time.c,v
retrieving revision 1.144
diff -u -p -r1.144 kern_time.c
--- kern_time.c 7 Oct 2020 17:53:44 -0000       1.144
+++ kern_time.c 7 Oct 2020 20:19:15 -0000
@@ -644,31 +644,25 @@ sys_setitimer(struct proc *p, void *v, r
 void
 realitexpire(void *arg)
 {
+       struct timespec cts, nts;
        struct process *pr = arg;
        struct itimerspec *tp = &pr->ps_timer[ITIMER_REAL];
 
        prsignal(pr, SIGALRM);
+
+       /* If it was a one-shot timer we're done. */
        if (!timespecisset(&tp->it_interval)) {
                timespecclear(&tp->it_value);
                return;
        }
-       for (;;) {
-               struct timespec cts, nts;
-               int timo;
 
+       /* Find the nearest future expiration point and reload the timer. */
+       getnanouptime(&cts);
+       while (timespeccmp(&tp->it_value, &cts, <=))
                timespecadd(&tp->it_value, &tp->it_interval, &tp->it_value);
-               getnanouptime(&cts);
-               if (timespeccmp(&tp->it_value, &cts, >)) {
-                       nts = tp->it_value;
-                       timespecsub(&nts, &cts, &nts);
-                       timo = tstohz(&nts) - 1;
-                       if (timo <= 0)
-                               timo = 1;
-                       if ((pr->ps_flags & PS_EXITING) == 0)
-                               timeout_add(&pr->ps_realit_to, timo);
-                       return;
-               }
-       }
+       timespecsub(&tp->it_value, &cts, &nts);
+       if ((pr->ps_flags & PS_EXITING) == 0)
+               timeout_add(&pr->ps_realit_to, MAX(1, tstohz(&nts) - 1));
 }
 
 /*

Reply via email to