svn commit: r315287 - in head: share/man/man9 sys/kern sys/sys
Eric van Gyzen
vangyzen at FreeBSD.org
Tue Mar 14 22:02:04 UTC 2017
Author: vangyzen
Date: Tue Mar 14 22:02:02 2017
New Revision: 315287
URL: https://svnweb.freebsd.org/changeset/base/315287
Log:
Add missing pieces of r315280
I moved this branch from github to a private server, and pulled from the
wrong one when committing r315280, so I failed to include two recent commits.
Thankfully, they were only cosmetic and were included in the review.
Specifically:
Add documentation, polish comments, and improve style(9).
Tested by: pho (r315280)
MFC after: 2 weeks
Sponsored by: Dell EMC
Differential Revision: https://reviews.freebsd.org/D9791
Modified:
head/share/man/man9/sleep.9
head/sys/kern/kern_tc.c
head/sys/kern/subr_sleepqueue.c
head/sys/sys/proc.h
Modified: head/share/man/man9/sleep.9
==============================================================================
--- head/share/man/man9/sleep.9 Tue Mar 14 20:57:54 2017 (r315286)
+++ head/share/man/man9/sleep.9 Tue Mar 14 22:02:02 2017 (r315287)
@@ -280,6 +280,21 @@ to
pay particular attention to ensure that no other threads wait on the
same
.Fa chan .
+.Pp
+If the timeout given by
+.Fa timo
+or
+.Fa sbt
+is based on an absolute real-time clock value,
+then the thread should copy the global
+.Va rtc_generation
+into its
+.Va td_rtcgen
+member before reading the RTC.
+If the real-time clock is adjusted, these functions will set
+.Va td_rtcgen
+to zero and return zero.
+The caller should reconsider its orientation with the new RTC value.
.Sh RETURN VALUES
When awakened by a call to
.Fn wakeup
@@ -298,6 +313,9 @@ the
.Fn msleep_spin ,
.Fn tsleep ,
and locking primitive sleep functions return 0.
+Zero can also be returned when the real-time clock is adjusted;
+see above regarding
+.Va td_rtcgen .
Otherwise, a non-zero error code is returned.
.Sh ERRORS
.Fn msleep ,
Modified: head/sys/kern/kern_tc.c
==============================================================================
--- head/sys/kern/kern_tc.c Tue Mar 14 20:57:54 2017 (r315286)
+++ head/sys/kern/kern_tc.c Tue Mar 14 22:02:02 2017 (r315287)
@@ -1269,6 +1269,15 @@ static bool
sleeping_on_old_rtc(struct thread *td)
{
+ /*
+ * td_rtcgen is modified by curthread when it is running,
+ * and by other threads in this function. By finding the thread
+ * on a sleepqueue and holding the lock on the sleepqueue
+ * chain, we guarantee that the thread is not running and that
+ * modifying td_rtcgen is safe. Setting td_rtcgen to zero informs
+ * the thread that it was woken due to a real-time clock adjustment.
+ * (The declaration of td_rtcgen refers to this comment.)
+ */
if (td->td_rtcgen != 0 && td->td_rtcgen != rtc_generation) {
td->td_rtcgen = 0;
return (true);
@@ -1299,6 +1308,7 @@ tc_setclock(struct timespec *ts)
/* XXX fiddle all the little crinkly bits around the fiords... */
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);
Modified: head/sys/kern/subr_sleepqueue.c
==============================================================================
--- head/sys/kern/subr_sleepqueue.c Tue Mar 14 20:57:54 2017 (r315286)
+++ head/sys/kern/subr_sleepqueue.c Tue Mar 14 22:02:02 2017 (r315287)
@@ -561,9 +561,21 @@ sleepq_switch(void *wchan, int pri)
/*
* If TDF_TIMEOUT is set, then our sleep has been timed out
* already but we are still on the sleep queue, so dequeue the
- * thread and return. Do the same if the real-time clock has
- * been adjusted since this thread calculated its timeout
- * based on that clock.
+ * thread and return.
+ *
+ * Do the same if the real-time clock has been adjusted since this
+ * thread calculated its timeout based on that clock. This handles
+ * the following race:
+ * - The Ts thread needs to sleep until an absolute real-clock time.
+ * It copies the global rtc_generation into curthread->td_rtcgen,
+ * reads the RTC, and calculates a sleep duration based on that time.
+ * See umtxq_sleep() for an example.
+ * - The Tc thread adjusts the RTC, bumps rtc_generation, and wakes
+ * threads that are sleeping until an absolute real-clock time.
+ * See tc_setclock() and the POSIX specification of clock_settime().
+ * - Ts reaches the code below. It holds the sleepqueue chain lock,
+ * so Tc has finished waking, so this thread must test td_rtcgen.
+ * (The declaration of td_rtcgen refers to this comment.)
*/
rtc_changed = td->td_rtcgen != 0 && td->td_rtcgen != rtc_generation;
if ((td->td_flags & TDF_TIMEOUT) || rtc_changed) {
@@ -899,6 +911,7 @@ sleepq_signal(void *wchan, int flags, in
static bool
match_any(struct thread *td __unused)
{
+
return (true);
}
Modified: head/sys/sys/proc.h
==============================================================================
--- head/sys/sys/proc.h Tue Mar 14 20:57:54 2017 (r315286)
+++ head/sys/sys/proc.h Tue Mar 14 22:02:02 2017 (r315287)
@@ -148,7 +148,7 @@ struct pargs {
* o - ktrace lock
* q - td_contested lock
* r - p_peers lock
- * s - by curthread, or by others when curthread is on sleepqueue
+ * s - see sleepq_switch(), sleeping_on_old_rtc(), and sleep(9)
* t - thread lock
* u - process stat lock
* w - process timer lock
More information about the svn-src-head
mailing list