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