summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric van Gyzen <vangyzen@FreeBSD.org>2017-03-14 19:06:44 +0000
committerSebastian Huber <sebastian.huber@embedded-brains.de>2017-10-12 07:04:11 +0200
commit952b42b643d66fbc88d45d51e4572102c9c00ba9 (patch)
treec48d76c86500b90b9185fb369b0451b7b53eea37
parenttimecounter: Merge FreeBSD change r310053 (diff)
downloadrtems-952b42b643d66fbc88d45d51e4572102c9c00ba9.tar.bz2
timecounter: Merge FreeBSD change r315280
When the RTC is adjusted, reevaluate absolute sleep times based on the RTC POSIX 2008 says this about clock_settime(2): If the value of the CLOCK_REALTIME clock is set via clock_settime(), the new value of the clock shall be used to determine the time of expiration for absolute time services based upon the CLOCK_REALTIME clock. This applies to the time at which armed absolute timers expire. If the absolute time requested at the invocation of such a time service is before the new value of the clock, the time service shall expire immediately as if the clock had reached the requested time normally. Setting the value of the CLOCK_REALTIME clock via clock_settime() shall have no effect on threads that are blocked waiting for a relative time service based upon this clock, including the nanosleep() function; nor on the expiration of relative timers based upon this clock. Consequently, these time services shall expire when the requested relative interval elapses, independently of the new or old value of the clock. When the real-time clock is adjusted, such as by clock_settime(3), wake any threads sleeping until an absolute real-clock time. Such a sleep is indicated by a non-zero td_rtcgen. The sleep functions will set that field to zero and return zero to tell the caller to reevaluate its sleep duration based on the new value of the clock. At present, this affects the following functions: pthread_cond_timedwait(3) pthread_mutex_timedlock(3) pthread_rwlock_timedrdlock(3) pthread_rwlock_timedwrlock(3) sem_timedwait(3) sem_clockwait_np(3) I'm working on adding clock_nanosleep(2), which will also be affected. Reported by: Sebastian Huber <sebastian.huber@embedded-brains.de> Reviewed by: jhb, kib MFC after: 2 weeks Relnotes: yes Sponsored by: Dell EMC Differential Revision: https://reviews.freebsd.org/D9791 Update #3175.
-rw-r--r--cpukit/score/src/kern_tc.c18
1 files changed, 18 insertions, 0 deletions
diff --git a/cpukit/score/src/kern_tc.c b/cpukit/score/src/kern_tc.c
index 2810fd88dd..81c2131008 100644
--- a/cpukit/score/src/kern_tc.c
+++ b/cpukit/score/src/kern_tc.c
@@ -56,7 +56,9 @@ __FBSDID("$FreeBSD r284178 2015-06-09T11:49:56Z$");
#include <sys/limits.h>
#include <sys/lock.h>
#include <sys/mutex.h>
+#include <sys/proc.h>
#include <sys/sbuf.h>
+#include <sys/sleepqueue.h>
#include <sys/sysctl.h>
#include <sys/syslog.h>
#include <sys/systm.h>
@@ -232,6 +234,8 @@ SYSCTL_PROC(_kern_timecounter, OID_AUTO, alloweddeviation,
sysctl_kern_timecounter_adjprecision, "I",
"Allowed time interval deviation in percents");
+volatile int rtc_generation = 1;
+
static int tc_chosen; /* Non-zero if a specific tc was chosen via sysctl. */
#endif /* __rtems__ */
@@ -1410,6 +1414,17 @@ tc_getfrequency(void)
return (timehands->th_counter->tc_frequency);
}
+static bool
+sleeping_on_old_rtc(struct thread *td)
+{
+
+ if (td->td_rtcgen != 0 && td->td_rtcgen != rtc_generation) {
+ td->td_rtcgen = 0;
+ return (true);
+ }
+ return (false);
+}
+
static struct mtx tc_setclock_mtx;
MTX_SYSINIT(tc_setclock_init, &tc_setclock_mtx, "tcsetc", MTX_SPIN);
#endif /* __rtems__ */
@@ -1446,6 +1461,9 @@ _Timecounter_Set_clock(const struct bintime *_bt,
#ifndef __rtems__
tc_windup(&bt);
mtx_unlock_spin(&tc_setclock_mtx);
+ /* Avoid rtc_generation == 0, since td_rtcgen == 0 is special. */
+ atomic_add_rel_int(&rtc_generation, 2);
+ sleepq_chains_remove_matching(sleeping_on_old_rtc);
if (timestepwarnings) {
nanotime(&taft);
log(LOG_INFO,