diff options
Diffstat (limited to 'sys/kern/kern_time.c')
-rw-r--r-- | sys/kern/kern_time.c | 41 |
1 files changed, 32 insertions, 9 deletions
diff --git a/sys/kern/kern_time.c b/sys/kern/kern_time.c index 76953229a0e..d34329ee642 100644 --- a/sys/kern/kern_time.c +++ b/sys/kern/kern_time.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_time.c,v 1.149 2020/10/25 01:55:18 cheloha Exp $ */ +/* $OpenBSD: kern_time.c,v 1.150 2020/11/10 17:26:54 cheloha Exp $ */ /* $NetBSD: kern_time.c,v 1.20 1996/02/18 11:57:06 fvdl Exp $ */ /* @@ -535,10 +535,11 @@ setitimer(int which, const struct itimerval *itv, struct itimerval *olditv) TIMEVAL_TO_TIMESPEC(&itv->it_interval, &its.it_interval); } - if (which != ITIMER_REAL) - mtx_enter(&itimer_mtx); - else + if (which == ITIMER_REAL) { + mtx_enter(&pr->ps_mtx); nanouptime(&now); + } else + mtx_enter(&itimer_mtx); if (olditv != NULL) oldits = *itimer; @@ -553,7 +554,9 @@ setitimer(int which, const struct itimerval *itv, struct itimerval *olditv) *itimer = its; } - if (which != ITIMER_REAL) + if (which == ITIMER_REAL) + mtx_leave(&pr->ps_mtx); + else mtx_leave(&itimer_mtx); if (olditv != NULL) { @@ -660,21 +663,41 @@ realitexpire(void *arg) struct timespec cts; struct process *pr = arg; struct itimerspec *tp = &pr->ps_timer[ITIMER_REAL]; + int need_signal = 0; + + mtx_enter(&pr->ps_mtx); - prsignal(pr, SIGALRM); + /* + * Do nothing if the timer was cancelled or rescheduled while we + * were entering the mutex. + */ + if (!timespecisset(&tp->it_value) || timeout_pending(&pr->ps_realit_to)) + goto out; - /* If it was a one-shot timer we're done. */ + /* The timer expired. We need to send the signal. */ + need_signal = 1; + + /* One-shot timers are not reloaded. */ if (!timespecisset(&tp->it_interval)) { timespecclear(&tp->it_value); - return; + goto out; } - /* Find the nearest future expiration point and restart the timeout. */ + /* + * Find the nearest future expiration point and restart + * the timeout. + */ nanouptime(&cts); while (timespeccmp(&tp->it_value, &cts, <=)) timespecadd(&tp->it_value, &tp->it_interval, &tp->it_value); if ((pr->ps_flags & PS_EXITING) == 0) timeout_at_ts(&pr->ps_realit_to, &tp->it_value); + +out: + mtx_leave(&pr->ps_mtx); + + if (need_signal) + prsignal(pr, SIGALRM); } /* |