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)); } /*