From 5e093a5bcb69ad1fb84c5898dff15e8820487256 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Wed, 22 Feb 2017 11:49:33 +0100 Subject: SLEEPQUEUE(9): Fix absolute timeouts The FreeBSD kernel timeouts are always based on the uptime. Thus, we have to use the relative watchdog. C_ABSOLUTE just means that the timeout value is already an uptime value. https://lists.freebsd.org/pipermail/freebsd-hackers/2017-February/050572.html --- freebsd/sys/kern/subr_sleepqueue.c | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/freebsd/sys/kern/subr_sleepqueue.c b/freebsd/sys/kern/subr_sleepqueue.c index 971f92dd..90023066 100644 --- a/freebsd/sys/kern/subr_sleepqueue.c +++ b/freebsd/sys/kern/subr_sleepqueue.c @@ -448,20 +448,39 @@ sleepq_set_timeout_sbt(void *wchan, sbintime_t sbt, sbintime_t pr, #else /* __rtems__ */ Per_CPU_Control *cpu_self; Thread_Control *executing; + ISR_lock_Context lock_context; + ISR_lock_Context lock_context_2; + Watchdog_Header *header; + uint64_t expire; cpu_self = _Thread_Dispatch_disable(); executing = _Per_CPU_Get_executing(cpu_self); BSD_ASSERT(_Watchdog_Get_state(&executing->Timer.Watchdog) == WATCHDOG_INACTIVE); - if ((flags & C_ABSOLUTE) == 0) { - _Thread_Timer_insert_relative(executing, cpu_self, sleepq_timeout, - (Watchdog_Interval)((sbt + tick_sbt - 1) / tick_sbt)); + _ISR_lock_ISR_disable_and_acquire(&executing->Timer.Lock, &lock_context); + + header = &cpu_self->Watchdog.Header[PER_CPU_WATCHDOG_RELATIVE]; + executing->Timer.header = header; + executing->Timer.Watchdog.routine = sleepq_timeout; + _Watchdog_Set_CPU(&executing->Timer.Watchdog, cpu_self); + + _Watchdog_Per_CPU_acquire_critical(cpu_self, &lock_context_2); + + if ((flags & C_ABSOLUTE) != 0) { + /* + * The FreeBSD uptime starts at one second, however, the + * relative watchdog ticks start at zero, see also TIMESEL(). + */ + expire = (sbt - SBT_1S + tick_sbt - 1) / tick_sbt; } else { - _Thread_Timer_insert_absolute(executing, cpu_self, sleepq_timeout, - _Watchdog_Ticks_from_sbintime(sbt)); + expire = (sbt + tick_sbt - 1) / tick_sbt; + expire += cpu_self->Watchdog.ticks; } + _Watchdog_Insert(header, &executing->Timer.Watchdog, expire); + _Watchdog_Per_CPU_release_critical(cpu_self, &lock_context_2); + _ISR_lock_Release_and_ISR_enable(&executing->Timer.Lock, &lock_context); _Thread_Dispatch_direct(cpu_self); #endif /* __rtems__ */ } -- cgit v1.2.3