Hi, We update the ITIMER_VIRTUAL and ITIMER_PROF per-process interval timers from hardclock(9). If a timer is enabled we call itimerdecr() to update and reload it as needed. If a timer has expired we then set a flag on the current thread to signal itself when returning to userspace.
However, there is a race here with setitimer(2). In hardclock(9) we check whether a timer is enabled *before* entering itimer_mtx in itimerdecr(), but once we have entered the mutex we don't double-check that the timer is still enabled. This is wrong. Another thread may have disabled the timer via setitimer(2) while we were entering the mutex. This patch adds the second check to itimerdecr(). If we lost the race and the timer is disabled we return 1 to indicate that the timer has not expired, i.e. that the thread should take no action. ok? Index: kern_time.c =================================================================== RCS file: /cvs/src/sys/kern/kern_time.c,v retrieving revision 1.134 diff -u -p -r1.134 kern_time.c --- kern_time.c 8 Aug 2020 01:01:26 -0000 1.134 +++ kern_time.c 9 Aug 2020 11:47:02 -0000 @@ -682,6 +682,20 @@ itimerdecr(struct itimerspec *itp, long NSEC_TO_TIMESPEC(nsec, &decrement); mtx_enter(&itimer_mtx); + + /* + * Double-check that the timer is enabled. We may have lost + * a race with another thread in setitimer(2) when entering + * itimer_mtx. + */ + if (!timespecisset(&itp->it_value)) { + mtx_leave(&itimer_mtx); + return (1); + } + + /* + * The timer is enabled. Update and reload it as needed. + */ timespecsub(&itp->it_value, &decrement, &itp->it_value); if (itp->it_value.tv_sec >= 0 && timespecisset(&itp->it_value)) { mtx_leave(&itimer_mtx);